root/arch/i386/i386/locore.s

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. proc_trampoline
  2. sigcode
  3. svr4_sigcode
  4. linux_sigcode
  5. freebsd_sigcode
  6. fillw
  7. kcopy
  8. ovbcopy
  9. bcopy
  10. memcpy
  11. copyout
  12. copyin
  13. copy_fault
  14. copyoutstr
  15. copyinstr
  16. copystr_fault
  17. copystr
  18. lgdt
  19. setjmp
  20. longjmp
  21. setrunqueue
  22. remrunqueue
  23. idle
  24. idle_loop
  25. idle_start
  26. idle_exit
  27. switch_error
  28. cpu_switch
  29. switch_exit
  30. savectx
  31. resume_iret
  32. resume_pop_ds
  33. resume_pop_es
  34. resume_pop_gs
  35. resume_pop_fs
  36. alltraps
  37. bzero
  38. sse2_pagezero
  39. i686_pagezero

    1 /*      $OpenBSD: locore.s,v 1.114 2007/05/29 23:02:02 tom Exp $        */
    2 /*      $NetBSD: locore.s,v 1.145 1996/05/03 19:41:19 christos Exp $    */
    3 
    4 /*-
    5  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.  All rights reserved.
    6  * Copyright (c) 1990 The Regents of the University of California.
    7  * All rights reserved.
    8  *
    9  * This code is derived from software contributed to Berkeley by
   10  * William Jolitz.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)locore.s    7.3 (Berkeley) 5/13/91
   37  */
   38 
   39 #include "npx.h"
   40 #include "assym.h"
   41 #include "apm.h"
   42 #include "lapic.h"
   43 #include "ioapic.h"
   44 #include "pctr.h"
   45 #include "ksyms.h"
   46 
   47 #include <sys/errno.h>
   48 #include <sys/syscall.h>
   49 #ifdef COMPAT_SVR4
   50 #include <compat/svr4/svr4_syscall.h>
   51 #endif
   52 #ifdef COMPAT_LINUX
   53 #include <compat/linux/linux_syscall.h>
   54 #endif
   55 #ifdef COMPAT_FREEBSD
   56 #include <compat/freebsd/freebsd_syscall.h>
   57 #endif
   58 
   59 #include <machine/cputypes.h>
   60 #include <machine/param.h>
   61 #include <machine/pte.h>
   62 #include <machine/segments.h>
   63 #include <machine/specialreg.h>
   64 #include <machine/trap.h>
   65 
   66 #include <dev/isa/isareg.h>
   67 
   68 #if NLAPIC > 0
   69 #include <machine/i82489reg.h>
   70 #endif
   71 
   72 /*
   73  * override user-land alignment before including asm.h
   74  */
   75 
   76 #define ALIGN_DATA      .align  4
   77 #define ALIGN_TEXT      .align  4,0x90  /* 4-byte boundaries, NOP-filled */
   78 #define SUPERALIGN_TEXT .align  16,0x90 /* 16-byte boundaries better for 486 */
   79 #define _ALIGN_TEXT     ALIGN_TEXT
   80 #include <machine/asm.h>
   81 
   82 #define CPL _C_LABEL(lapic_tpr)
   83 
   84 #define GET_CURPCB(reg)                                 \
   85         movl    CPUVAR(CURPCB), reg
   86 
   87 #define SET_CURPCB(reg)                                 \
   88         movl    reg, CPUVAR(CURPCB)
   89 
   90 #define CHECK_ASTPENDING(treg)                          \
   91         movl    CPUVAR(CURPROC),treg            ;       \
   92         cmpl    $0, treg                        ;       \
   93         je      1f                              ;       \
   94         cmpl    $0,P_MD_ASTPENDING(treg)        ;       \
   95         1:
   96 
   97 #define CLEAR_ASTPENDING(cpreg)                         \
   98         movl    $0,P_MD_ASTPENDING(cpreg)
   99 
  100 /*
  101  * These are used on interrupt or trap entry or exit.
  102  */
  103 #define INTRENTRY \
  104         pushl   %eax            ; \
  105         pushl   %ecx            ; \
  106         pushl   %edx            ; \
  107         pushl   %ebx            ; \
  108         pushl   %ebp            ; \
  109         pushl   %esi            ; \
  110         pushl   %edi            ; \
  111         pushl   %ds             ; \
  112         pushl   %es             ; \
  113         pushl   %gs             ; \
  114         movl    $GSEL(GDATA_SEL, SEL_KPL),%eax  ; \
  115         movw    %ax,%ds         ; \
  116         movw    %ax,%es         ; \
  117         movw    %ax,%gs         ; \
  118         pushl   %fs             ; \
  119         movl    $GSEL(GCPU_SEL, SEL_KPL),%eax   ; \
  120         movw    %ax,%fs
  121 #define INTRFASTEXIT \
  122         popl    %fs             ; \
  123         popl    %gs             ; \
  124         popl    %es             ; \
  125         popl    %ds             ; \
  126         popl    %edi            ; \
  127         popl    %esi            ; \
  128         popl    %ebp            ; \
  129         popl    %ebx            ; \
  130         popl    %edx            ; \
  131         popl    %ecx            ; \
  132         popl    %eax            ; \
  133         sti                     ; \
  134         addl    $8,%esp         ; \
  135         iret
  136 
  137 
  138 /*
  139  * PTmap is recursive pagemap at top of virtual address space.
  140  * Within PTmap, the page directory can be found (third indirection).
  141  */
  142         .globl  _C_LABEL(PTmap), _C_LABEL(PTD), _C_LABEL(PTDpde)
  143         .set    _C_LABEL(PTmap), (PDSLOT_PTE << PDSHIFT)
  144         .set    _C_LABEL(PTD), (_C_LABEL(PTmap) + PDSLOT_PTE * NBPG)
  145         .set    _C_LABEL(PTDpde), (_C_LABEL(PTD) + PDSLOT_PTE * 4)      # XXX 4 == sizeof pde
  146 
  147 /*
  148  * APTmap, APTD is the alternate recursive pagemap.
  149  * It's used when modifying another process's page tables.
  150  */
  151         .globl  _C_LABEL(APTmap), _C_LABEL(APTD), _C_LABEL(APTDpde)
  152         .set    _C_LABEL(APTmap), (PDSLOT_APTE << PDSHIFT)
  153         .set    _C_LABEL(APTD), (_C_LABEL(APTmap) + PDSLOT_APTE * NBPG)
  154         # XXX 4 == sizeof pde
  155         .set    _C_LABEL(APTDpde), (_C_LABEL(PTD) + PDSLOT_APTE * 4)
  156 
  157 /*
  158  * Initialization
  159  */
  160         .data
  161 
  162         .globl  _C_LABEL(cpu), _C_LABEL(cpu_id), _C_LABEL(cpu_vendor)
  163         .globl  _C_LABEL(cpu_brandstr)
  164         .globl  _C_LABEL(cpuid_level)
  165         .globl  _C_LABEL(cpu_miscinfo)
  166         .globl  _C_LABEL(cpu_feature), _C_LABEL(cpu_ecxfeature)
  167         .globl  _C_LABEL(cpu_cache_eax), _C_LABEL(cpu_cache_ebx)
  168         .globl  _C_LABEL(cpu_cache_ecx), _C_LABEL(cpu_cache_edx)
  169         .globl  _C_LABEL(cold), _C_LABEL(cnvmem), _C_LABEL(extmem)
  170         .globl  _C_LABEL(esym)
  171         .globl  _C_LABEL(boothowto), _C_LABEL(bootdev), _C_LABEL(atdevbase)
  172         .globl  _C_LABEL(proc0paddr), _C_LABEL(PTDpaddr), _C_LABEL(PTDsize)
  173         .globl  _C_LABEL(gdt)
  174         .globl  _C_LABEL(bootapiver), _C_LABEL(bootargc), _C_LABEL(bootargv)
  175         .globl  _C_LABEL(lapic_tpr)
  176 
  177 #if NLAPIC > 0
  178 #ifdef __ELF__
  179         .align NBPG
  180 #else
  181         .align 12
  182 #endif
  183         .globl _C_LABEL(local_apic), _C_LABEL(lapic_id)
  184 _C_LABEL(local_apic):
  185         .space  LAPIC_ID
  186 _C_LABEL(lapic_id):
  187         .long   0x00000000
  188         .space  LAPIC_TPRI-(LAPIC_ID+4)
  189 _C_LABEL(lapic_tpr):
  190         .space  LAPIC_PPRI-LAPIC_TPRI
  191 _C_LABEL(lapic_ppr):
  192         .space  LAPIC_ISR-LAPIC_PPRI
  193 _C_LABEL(lapic_isr):
  194         .space  NBPG-LAPIC_ISR
  195 #else
  196 _C_LABEL(lapic_tpr):
  197         .long   0
  198 #endif
  199 
  200 _C_LABEL(cpu):          .long   0       # are we 386, 386sx, 486, 586 or 686
  201 _C_LABEL(cpu_id):       .long   0       # saved from 'cpuid' instruction
  202 _C_LABEL(cpu_miscinfo): .long   0       # misc info (apic/brand id) from 'cpuid'
  203 _C_LABEL(cpu_feature):  .long   0       # feature flags from 'cpuid' instruction
  204 _C_LABEL(cpu_ecxfeature):.long  0       # extended feature flags from 'cpuid'
  205 _C_LABEL(cpuid_level):  .long   -1      # max. lvl accepted by 'cpuid' insn
  206 _C_LABEL(cpu_cache_eax):.long   0
  207 _C_LABEL(cpu_cache_ebx):.long   0
  208 _C_LABEL(cpu_cache_ecx):.long   0
  209 _C_LABEL(cpu_cache_edx):.long   0
  210 _C_LABEL(cpu_vendor): .space 16 # vendor string returned by 'cpuid' instruction
  211 _C_LABEL(cpu_brandstr): .space 48 # brand string returned by 'cpuid'
  212 _C_LABEL(cold):         .long   1       # cold till we are not
  213 _C_LABEL(esym):         .long   0       # ptr to end of syms
  214 _C_LABEL(cnvmem):       .long   0       # conventional memory size
  215 _C_LABEL(extmem):       .long   0       # extended memory size
  216 _C_LABEL(atdevbase):    .long   0       # location of start of iomem in virtual
  217 _C_LABEL(bootapiver):   .long   0       # /boot API version
  218 _C_LABEL(bootargc):     .long   0       # /boot argc
  219 _C_LABEL(bootargv):     .long   0       # /boot argv
  220 _C_LABEL(bootdev):      .long   0       # device we booted from
  221 _C_LABEL(proc0paddr):   .long   0
  222 _C_LABEL(PTDpaddr):     .long   0       # paddr of PTD, for libkvm
  223 _C_LABEL(PTDsize):      .long   NBPG    # size of PTD, for libkvm
  224 
  225         .space 512
  226 tmpstk:
  227 
  228 
  229 #define RELOC(x)        ((x) - KERNBASE)
  230 
  231         .text
  232         .globl  start
  233         .globl  _C_LABEL(kernel_text)
  234         _C_LABEL(kernel_text) = KERNTEXTOFF
  235 start:  movw    $0x1234,0x472                   # warm boot
  236 
  237         /*
  238          * Load parameters from stack (howto, bootdev, unit, bootapiver, esym).
  239          * note: (%esp) is return address of boot
  240          * (If we want to hold onto /boot, it's physical %esp up to _end.)
  241          */
  242         movl    4(%esp),%eax
  243         movl    %eax,RELOC(_C_LABEL(boothowto))
  244         movl    8(%esp),%eax
  245         movl    %eax,RELOC(_C_LABEL(bootdev))
  246         movl    16(%esp),%eax
  247         testl   %eax,%eax
  248         jz      1f
  249         addl    $KERNBASE,%eax
  250 1:      movl    %eax,RELOC(_C_LABEL(esym))
  251 
  252         movl    12(%esp),%eax
  253         movl    %eax,RELOC(_C_LABEL(bootapiver))
  254         movl    28(%esp), %eax
  255         movl    %eax, RELOC(_C_LABEL(bootargc))
  256         movl    32(%esp), %eax
  257         movl    %eax, RELOC(_C_LABEL(bootargv))
  258 
  259         /* First, reset the PSL. */
  260         pushl   $PSL_MBO
  261         popfl
  262 
  263         /* Clear segment registers; null until proc0 setup */
  264         xorl    %eax,%eax
  265         movw    %ax,%fs
  266         movw    %ax,%gs
  267 
  268         /* Find out our CPU type. */
  269 
  270 try386: /* Try to toggle alignment check flag; does not exist on 386. */
  271         pushfl
  272         popl    %eax
  273         movl    %eax,%ecx
  274         orl     $PSL_AC,%eax
  275         pushl   %eax
  276         popfl
  277         pushfl
  278         popl    %eax
  279         xorl    %ecx,%eax
  280         andl    $PSL_AC,%eax
  281         pushl   %ecx
  282         popfl
  283 
  284         testl   %eax,%eax
  285         jnz     try486
  286 
  287         /*
  288          * Try the test of a NexGen CPU -- ZF will not change on a DIV
  289          * instruction on a NexGen, it will on an i386.  Documented in
  290          * Nx586 Processor Recognition Application Note, NexGen, Inc.
  291          */
  292         movl    $0x5555,%eax
  293         xorl    %edx,%edx
  294         movl    $2,%ecx
  295         divl    %ecx
  296         jnz     is386
  297 
  298 isnx586:
  299         /*
  300          * Don't try cpuid, as Nx586s reportedly don't support the
  301          * PSL_ID bit.
  302          */
  303         movl    $CPU_NX586,RELOC(_C_LABEL(cpu))
  304         jmp     2f
  305 
  306 is386:
  307         movl    $CPU_386,RELOC(_C_LABEL(cpu))
  308         jmp     2f
  309 
  310 try486: /* Try to toggle identification flag; does not exist on early 486s. */
  311         pushfl
  312         popl    %eax
  313         movl    %eax,%ecx
  314         xorl    $PSL_ID,%eax
  315         pushl   %eax
  316         popfl
  317         pushfl
  318         popl    %eax
  319         xorl    %ecx,%eax
  320         andl    $PSL_ID,%eax
  321         pushl   %ecx
  322         popfl
  323 
  324         testl   %eax,%eax
  325         jnz     try586
  326 is486:  movl    $CPU_486,RELOC(_C_LABEL(cpu))
  327 
  328         /*
  329          * Check Cyrix CPU
  330          * Cyrix CPUs do not change the undefined flags following
  331          * execution of the divide instruction which divides 5 by 2.
  332          *
  333          * Note: CPUID is enabled on M2, so it passes another way.
  334          */
  335         pushfl
  336         movl    $0x5555, %eax
  337         xorl    %edx, %edx
  338         movl    $2, %ecx
  339         clc
  340         divl    %ecx
  341         jnc     trycyrix486
  342         popfl
  343         jmp     2f
  344 trycyrix486:
  345         movl    $CPU_6x86,RELOC(_C_LABEL(cpu))  # set CPU type
  346         /*
  347          * Check for Cyrix 486 CPU by seeing if the flags change during a
  348          * divide.  This is documented in the Cx486SLC/e SMM Programmer's
  349          * Guide.
  350          */
  351         xorl    %edx,%edx
  352         cmpl    %edx,%edx               # set flags to known state
  353         pushfl
  354         popl    %ecx                    # store flags in ecx
  355         movl    $-1,%eax
  356         movl    $4,%ebx
  357         divl    %ebx                    # do a long division
  358         pushfl
  359         popl    %eax
  360         xorl    %ecx,%eax               # are the flags different?
  361         testl   $0x8d5,%eax             # only check C|PF|AF|Z|N|V
  362         jne     2f                      # yes; must not be Cyrix CPU
  363         movl    $CPU_486DLC,RELOC(_C_LABEL(cpu))        # set CPU type
  364 
  365 #ifndef CYRIX_CACHE_WORKS
  366         /* Disable caching of the ISA hole only. */
  367         invd
  368         movb    $CCR0,%al               # Configuration Register index (CCR0)
  369         outb    %al,$0x22
  370         inb     $0x23,%al
  371         orb     $(CCR0_NC1|CCR0_BARB),%al
  372         movb    %al,%ah
  373         movb    $CCR0,%al
  374         outb    %al,$0x22
  375         movb    %ah,%al
  376         outb    %al,$0x23
  377         invd
  378 #else /* CYRIX_CACHE_WORKS */
  379         /* Set cache parameters */
  380         invd                            # Start with guaranteed clean cache
  381         movb    $CCR0,%al               # Configuration Register index (CCR0)
  382         outb    %al,$0x22
  383         inb     $0x23,%al
  384         andb    $~CCR0_NC0,%al
  385 #ifndef CYRIX_CACHE_REALLY_WORKS
  386         orb     $(CCR0_NC1|CCR0_BARB),%al
  387 #else
  388         orb     $CCR0_NC1,%al
  389 #endif
  390         movb    %al,%ah
  391         movb    $CCR0,%al
  392         outb    %al,$0x22
  393         movb    %ah,%al
  394         outb    %al,$0x23
  395         /* clear non-cacheable region 1 */
  396         movb    $(NCR1+2),%al
  397         outb    %al,$0x22
  398         movb    $NCR_SIZE_0K,%al
  399         outb    %al,$0x23
  400         /* clear non-cacheable region 2 */
  401         movb    $(NCR2+2),%al
  402         outb    %al,$0x22
  403         movb    $NCR_SIZE_0K,%al
  404         outb    %al,$0x23
  405         /* clear non-cacheable region 3 */
  406         movb    $(NCR3+2),%al
  407         outb    %al,$0x22
  408         movb    $NCR_SIZE_0K,%al
  409         outb    %al,$0x23
  410         /* clear non-cacheable region 4 */
  411         movb    $(NCR4+2),%al
  412         outb    %al,$0x22
  413         movb    $NCR_SIZE_0K,%al
  414         outb    %al,$0x23
  415         /* enable caching in CR0 */
  416         movl    %cr0,%eax
  417         andl    $~(CR0_CD|CR0_NW),%eax
  418         movl    %eax,%cr0
  419         invd
  420 #endif /* CYRIX_CACHE_WORKS */
  421 
  422         jmp     2f
  423 
  424 try586: /* Use the `cpuid' instruction. */
  425         xorl    %eax,%eax
  426         cpuid
  427         movl    %eax,RELOC(_C_LABEL(cpuid_level))
  428         movl    %ebx,RELOC(_C_LABEL(cpu_vendor))        # store vendor string
  429         movl    %edx,RELOC(_C_LABEL(cpu_vendor))+4
  430         movl    %ecx,RELOC(_C_LABEL(cpu_vendor))+8
  431         movl    $0,  RELOC(_C_LABEL(cpu_vendor))+12
  432 
  433         movl    $1,%eax
  434         cpuid
  435         movl    %eax,RELOC(_C_LABEL(cpu_id))    # store cpu_id and features
  436         movl    %ebx,RELOC(_C_LABEL(cpu_miscinfo))
  437         movl    %edx,RELOC(_C_LABEL(cpu_feature))
  438         movl    %ecx,RELOC(_C_LABEL(cpu_ecxfeature))
  439 
  440         movl    RELOC(_C_LABEL(cpuid_level)),%eax
  441         cmp     $2,%eax
  442         jl      1f
  443 
  444         movl    $2,%eax
  445         cpuid
  446 /*
  447         cmp     $1,%al
  448         jne     1f
  449 */
  450 
  451         movl    %eax,RELOC(_C_LABEL(cpu_cache_eax))
  452         movl    %ebx,RELOC(_C_LABEL(cpu_cache_ebx))
  453         movl    %ecx,RELOC(_C_LABEL(cpu_cache_ecx))
  454         movl    %edx,RELOC(_C_LABEL(cpu_cache_edx))
  455 
  456 1:
  457         /* Check if brand identification string is supported */
  458         movl    $0x80000000,%eax
  459         cpuid
  460         cmpl    $0x80000000,%eax
  461         jbe     2f
  462         movl    $0x80000002,%eax
  463         cpuid
  464         movl    %eax,RELOC(_C_LABEL(cpu_brandstr))
  465         movl    %ebx,RELOC(_C_LABEL(cpu_brandstr))+4
  466         movl    %ecx,RELOC(_C_LABEL(cpu_brandstr))+8
  467         movl    %edx,RELOC(_C_LABEL(cpu_brandstr))+12
  468         movl    $0x80000003,%eax
  469         cpuid
  470         movl    %eax,RELOC(_C_LABEL(cpu_brandstr))+16
  471         movl    %ebx,RELOC(_C_LABEL(cpu_brandstr))+20
  472         movl    %ecx,RELOC(_C_LABEL(cpu_brandstr))+24
  473         movl    %edx,RELOC(_C_LABEL(cpu_brandstr))+28
  474         movl    $0x80000004,%eax
  475         cpuid
  476         movl    %eax,RELOC(_C_LABEL(cpu_brandstr))+32
  477         movl    %ebx,RELOC(_C_LABEL(cpu_brandstr))+36
  478         movl    %ecx,RELOC(_C_LABEL(cpu_brandstr))+40
  479         andl    $0x00ffffff,%edx        /* Shouldn't be necessary */
  480         movl    %edx,RELOC(_C_LABEL(cpu_brandstr))+44
  481 
  482 2:
  483         /*
  484          * Finished with old stack; load new %esp now instead of later so we
  485          * can trace this code without having to worry about the trace trap
  486          * clobbering the memory test or the zeroing of the bss+bootstrap page
  487          * tables.
  488          *
  489          * The boot program should check:
  490          *      text+data <= &stack_variable - more_space_for_stack
  491          *      text+data+bss+pad+space_for_page_tables <= end_of_memory
  492          * Oops, the gdt is in the carcass of the boot program so clearing
  493          * the rest of memory is still not possible.
  494          */
  495         movl    $RELOC(tmpstk),%esp     # bootstrap stack end location
  496 
  497 /*
  498  * Virtual address space of kernel:
  499  *
  500  * text | data | bss | [syms] | proc0 stack | page dir     | Sysmap
  501  *                            0             1       2      3
  502  */
  503 #define PROC0STACK      ((0)            * NBPG)
  504 #define PROC0PDIR       ((  UPAGES)     * NBPG)
  505 #define SYSMAP          ((1+UPAGES)     * NBPG)
  506 #define TABLESIZE       ((1+UPAGES) * NBPG) /* + _C_LABEL(nkpde) * NBPG */
  507 
  508         /* Find end of kernel image. */
  509         movl    $RELOC(_C_LABEL(end)),%edi
  510 #if (defined(DDB) || NKSYMS > 0) && !defined(SYMTAB_SPACE)
  511         /* Save the symbols (if loaded). */
  512         movl    RELOC(_C_LABEL(esym)),%eax
  513         testl   %eax,%eax
  514         jz      1f
  515         subl    $KERNBASE,%eax
  516         movl    %eax,%edi
  517 1:
  518 #endif
  519 
  520         /* Calculate where to start the bootstrap tables. */
  521         movl    %edi,%esi                       # edi = esym ? esym : end
  522         addl    $PGOFSET, %esi                  # page align up
  523         andl    $~PGOFSET, %esi
  524 
  525         /*
  526          * Calculate the size of the kernel page table directory, and
  527          * how many entries it will have.
  528          */
  529         movl    RELOC(_C_LABEL(nkpde)),%ecx     # get nkpde
  530         cmpl    $NKPTP_MIN,%ecx                 # larger than min?
  531         jge     1f
  532         movl    $NKPTP_MIN,%ecx                 # set at min
  533         jmp     2f
  534 1:      cmpl    $NKPTP_MAX,%ecx                 # larger than max?
  535         jle     2f
  536         movl    $NKPTP_MAX,%ecx
  537 2:      movl    %ecx,RELOC(_C_LABEL(nkpde))     # and store it back
  538 
  539         /* Clear memory for bootstrap tables. */
  540         shll    $PGSHIFT,%ecx
  541         addl    $TABLESIZE,%ecx
  542         addl    %esi,%ecx                       # end of tables
  543         subl    %edi,%ecx                       # size of tables
  544         shrl    $2,%ecx
  545         xorl    %eax, %eax
  546         cld
  547         rep
  548         stosl
  549 
  550 /*
  551  * fillkpt
  552  *      eax = pte (page frame | control | status)
  553  *      ebx = page table address
  554  *      ecx = number of pages to map
  555  */
  556 #define fillkpt         \
  557 1:      movl    %eax,(%ebx)     ; \
  558         addl    $NBPG,%eax      ; /* increment physical address */ \
  559         addl    $4,%ebx         ; /* next pte */ \
  560         loop    1b              ;
  561 
  562 /*
  563  * Build initial page tables.
  564  */
  565         /* Calculate end of text segment, rounded to a page. */
  566         leal    (RELOC(_C_LABEL(etext))+PGOFSET),%edx
  567         andl    $~PGOFSET,%edx
  568 
  569         /* Skip over the first 2MB. */
  570         movl    $RELOC(KERNTEXTOFF),%eax
  571         movl    %eax,%ecx
  572         shrl    $PGSHIFT,%ecx
  573         leal    (SYSMAP)(%esi,%ecx,4),%ebx
  574 
  575         /* Map the kernel text read-only. */
  576         movl    %edx,%ecx
  577         subl    %eax,%ecx
  578         shrl    $PGSHIFT,%ecx
  579 #ifdef DDB
  580         orl     $(PG_V|PG_KW),%eax
  581 #else
  582         orl     $(PG_V|PG_KR),%eax
  583 #endif
  584         fillkpt
  585 
  586         /* Map the data, BSS, and bootstrap tables read-write. */
  587         leal    (PG_V|PG_KW)(%edx),%eax
  588         movl    RELOC(_C_LABEL(nkpde)),%ecx
  589         shll    $PGSHIFT,%ecx
  590         addl    $TABLESIZE,%ecx
  591         addl    %esi,%ecx                               # end of tables
  592         subl    %edx,%ecx                               # subtract end of text
  593         shrl    $PGSHIFT,%ecx
  594         fillkpt
  595 
  596         /* Map ISA I/O memory. */
  597         movl    $(IOM_BEGIN|PG_V|PG_KW/*|PG_N*/),%eax   # having these bits set
  598         movl    $(IOM_SIZE>>PGSHIFT),%ecx               # for this many pte s,
  599         fillkpt
  600 
  601 /*
  602  * Construct a page table directory.
  603 */
  604         movl    RELOC(_C_LABEL(nkpde)),%ecx             # count of pde s,
  605         leal    (PROC0PDIR+0*4)(%esi),%ebx              # where temp maps!
  606         leal    (SYSMAP+PG_V|PG_KW)(%esi),%eax          # pte for KPT in proc 0
  607         fillkpt
  608 
  609 /*
  610  * Map kernel PDEs: this is the real mapping used
  611  * after the temp mapping outlives its usefulness.
  612  */
  613         movl    RELOC(_C_LABEL(nkpde)),%ecx             # count of pde s,
  614         leal    (PROC0PDIR+PDSLOT_KERN*4)(%esi),%ebx    # map them high
  615         leal    (SYSMAP+PG_V|PG_KW)(%esi),%eax          # pte for KPT in proc 0
  616         fillkpt
  617 
  618         /* Install a PDE recursively mapping page directory as a page table! */
  619         leal    (PROC0PDIR+PG_V|PG_KW)(%esi),%eax       # pte for ptd
  620         movl    %eax,(PROC0PDIR+PDSLOT_PTE*4)(%esi)     # recursive PD slot
  621 
  622         /* Save phys. addr of PTD, for libkvm. */
  623         leal    (PROC0PDIR)(%esi),%eax          # phys address of ptd in proc 0
  624         movl    %eax,RELOC(_C_LABEL(PTDpaddr))
  625 
  626         /* Load base of page directory and enable mapping. */
  627         movl    %eax,%cr3               # load ptd addr into mmu
  628         movl    %cr0,%eax               # get control word
  629                                         # enable paging & NPX emulation
  630         orl     $(CR0_PE|CR0_PG|CR0_NE|CR0_TS|CR0_EM|CR0_MP),%eax
  631         movl    %eax,%cr0               # and let's page NOW!
  632 
  633         pushl   $begin                  # jump to high mem
  634         ret
  635 
  636 begin:
  637         /* Now running relocated at KERNBASE.  Remove double mapping. */
  638         movl    _C_LABEL(nkpde),%ecx            # for this many pde s,
  639         leal    (PROC0PDIR+0*4)(%esi),%ebx      # which is where temp maps!
  640         addl    $(KERNBASE), %ebx       # now use relocated address
  641 1:      movl    $0,(%ebx)
  642         addl    $4,%ebx # next pde
  643         loop    1b
  644 
  645         /* Relocate atdevbase. */
  646         movl    _C_LABEL(nkpde),%edx
  647         shll    $PGSHIFT,%edx
  648         addl    $(TABLESIZE+KERNBASE),%edx
  649         addl    %esi,%edx
  650         movl    %edx,_C_LABEL(atdevbase)
  651 
  652         /* Set up bootstrap stack. */
  653         leal    (PROC0STACK+KERNBASE)(%esi),%eax
  654         movl    %eax,_C_LABEL(proc0paddr)
  655         leal    (USPACE-FRAMESIZE)(%eax),%esp
  656         leal    (PROC0PDIR)(%esi),%ebx  # phys address of ptd in proc 0
  657         movl    %ebx,PCB_CR3(%eax)      # pcb->pcb_cr3
  658         xorl    %ebp,%ebp               # mark end of frames
  659 
  660         movl    _C_LABEL(nkpde),%eax
  661         shll    $PGSHIFT,%eax
  662         addl    $TABLESIZE,%eax
  663         addl    %esi,%eax               # skip past stack and page tables
  664         pushl   %eax
  665         call    _C_LABEL(init386)       # wire 386 chip for unix operation
  666         addl    $4,%esp
  667 
  668         call    _C_LABEL(main)
  669 
  670 NENTRY(proc_trampoline)
  671 #ifdef MULTIPROCESSOR
  672         call    _C_LABEL(proc_trampoline_mp)
  673 #endif
  674         movl    $IPL_NONE,CPL
  675         pushl   %ebx
  676         call    *%esi
  677         addl    $4,%esp
  678         INTRFASTEXIT
  679         /* NOTREACHED */
  680 
  681 /*****************************************************************************/
  682 
  683 /*
  684  * Signal trampoline; copied to top of user stack.
  685  */
  686 NENTRY(sigcode)
  687         movl    SIGF_FPSTATE(%esp),%esi # FPU state area if need saving
  688         testl   %esi,%esi
  689         jz      1f
  690         fnsave  (%esi)
  691 1:      call    *SIGF_HANDLER(%esp)
  692         testl   %esi,%esi
  693         jz      2f
  694         frstor  (%esi)
  695         jmp     2f
  696 
  697         .globl  _C_LABEL(sigcode_xmm)
  698 _C_LABEL(sigcode_xmm):
  699         movl    SIGF_FPSTATE(%esp),%esi # FPU state area if need saving
  700         testl   %esi,%esi
  701         jz      1f
  702         fxsave  (%esi)
  703         fninit
  704 1:      call    *SIGF_HANDLER(%esp)
  705         testl   %esi,%esi
  706         jz      2f
  707         fxrstor (%esi)
  708 
  709 2:      leal    SIGF_SC(%esp),%eax      # scp (the call may have clobbered the
  710                                         # copy at SIGF_SCP(%esp))
  711         pushl   %eax
  712         pushl   %eax                    # junk to fake return address
  713         movl    $SYS_sigreturn,%eax
  714         int     $0x80                   # enter kernel with args on stack
  715         movl    $SYS_exit,%eax
  716         int     $0x80                   # exit if sigreturn fails
  717         .globl  _C_LABEL(esigcode)
  718 _C_LABEL(esigcode):
  719 
  720 /*****************************************************************************/
  721 
  722 #ifdef COMPAT_SVR4
  723 NENTRY(svr4_sigcode)
  724         call    *SVR4_SIGF_HANDLER(%esp)
  725         leal    SVR4_SIGF_UC(%esp),%eax # ucp (the call may have clobbered the
  726                                         # copy at SIGF_UCP(%esp))
  727         pushl   %eax
  728         pushl   $1                      # setcontext(p) == syscontext(1, p)
  729         pushl   %eax                    # junk to fake return address
  730         movl    $SVR4_SYS_context,%eax
  731         int     $0x80                   # enter kernel with args on stack
  732         movl    $SVR4_SYS_exit,%eax
  733         int     $0x80                   # exit if sigreturn fails
  734         .globl  _C_LABEL(svr4_esigcode)
  735 _C_LABEL(svr4_esigcode):
  736 #endif
  737 
  738 /*****************************************************************************/
  739 
  740 #ifdef COMPAT_LINUX
  741 /*
  742  * Signal trampoline; copied to top of user stack.
  743  */
  744 NENTRY(linux_sigcode)
  745         call    *LINUX_SIGF_HANDLER(%esp)
  746         leal    LINUX_SIGF_SC(%esp),%ebx # scp (the call may have clobbered the
  747                                         # copy at SIGF_SCP(%esp))
  748         pushl   %eax                    # junk to fake return address
  749         movl    $LINUX_SYS_sigreturn,%eax
  750         int     $0x80                   # enter kernel with args on stack
  751         movl    $LINUX_SYS_exit,%eax
  752         int     $0x80                   # exit if sigreturn fails
  753         .globl  _C_LABEL(linux_esigcode)
  754 _C_LABEL(linux_esigcode):
  755 #endif
  756 
  757 /*****************************************************************************/
  758 
  759 #ifdef COMPAT_FREEBSD
  760 /*
  761  * Signal trampoline; copied to top of user stack.
  762  */
  763 NENTRY(freebsd_sigcode)
  764         call    *FREEBSD_SIGF_HANDLER(%esp)
  765         leal    FREEBSD_SIGF_SC(%esp),%eax # scp (the call may have clobbered
  766                                         # the copy at SIGF_SCP(%esp))
  767         pushl   %eax
  768         pushl   %eax                    # junk to fake return address
  769         movl    $FREEBSD_SYS_sigreturn,%eax
  770         int     $0x80                   # enter kernel with args on stack
  771         movl    $FREEBSD_SYS_exit,%eax
  772         int     $0x80                   # exit if sigreturn fails
  773         .globl  _C_LABEL(freebsd_esigcode)
  774 _C_LABEL(freebsd_esigcode):
  775 #endif
  776 
  777 /*****************************************************************************/
  778 
  779 /*
  780  * The following primitives are used to fill and copy regions of memory.
  781  */
  782 
  783 /*
  784  * fillw(short pattern, caddr_t addr, size_t len);
  785  * Write len copies of pattern at addr.
  786  */
  787 ENTRY(fillw)
  788         pushl   %edi
  789         movl    8(%esp),%eax
  790         movl    12(%esp),%edi
  791         movw    %ax,%cx
  792         rorl    $16,%eax
  793         movw    %cx,%ax
  794         cld
  795         movl    16(%esp),%ecx
  796         shrl    %ecx                    # do longwords
  797         rep
  798         stosl
  799         movl    16(%esp),%ecx
  800         andl    $1,%ecx                 # do remainder
  801         rep
  802         stosw
  803         popl    %edi
  804         ret
  805 
  806 
  807 /* Frame pointer reserve on stack. */
  808 #ifdef DDB
  809 #define FPADD 4
  810 #else
  811 #define FPADD 0
  812 #endif
  813 
  814 /*
  815  * kcopy(caddr_t from, caddr_t to, size_t len);
  816  * Copy len bytes, abort on fault.
  817  */
  818 ENTRY(kcopy)
  819 #ifdef DDB
  820         pushl   %ebp
  821         movl    %esp,%ebp
  822 #endif
  823         pushl   %esi
  824         pushl   %edi
  825         GET_CURPCB(%eax)                # load curpcb into eax and set on-fault
  826         pushl   PCB_ONFAULT(%eax)
  827         movl    $_C_LABEL(copy_fault), PCB_ONFAULT(%eax)
  828 
  829         movl    16+FPADD(%esp),%esi
  830         movl    20+FPADD(%esp),%edi
  831         movl    24+FPADD(%esp),%ecx
  832         movl    %edi,%eax
  833         subl    %esi,%eax
  834         cmpl    %ecx,%eax               # overlapping?
  835         jb      1f
  836         cld                             # nope, copy forward
  837         shrl    $2,%ecx                 # copy by 32-bit words
  838         rep
  839         movsl
  840         movl    24+FPADD(%esp),%ecx
  841         andl    $3,%ecx                 # any bytes left?
  842         rep
  843         movsb
  844 
  845         GET_CURPCB(%edx)                # XXX save curpcb?
  846         popl    PCB_ONFAULT(%edx)
  847         popl    %edi
  848         popl    %esi
  849         xorl    %eax,%eax
  850 #ifdef DDB
  851         leave
  852 #endif
  853         ret
  854 
  855         ALIGN_TEXT
  856 1:      addl    %ecx,%edi               # copy backward
  857         addl    %ecx,%esi
  858         std
  859         andl    $3,%ecx                 # any fractional bytes?
  860         decl    %edi
  861         decl    %esi
  862         rep
  863         movsb
  864         movl    24+FPADD(%esp),%ecx     # copy remainder by 32-bit words
  865         shrl    $2,%ecx
  866         subl    $3,%esi
  867         subl    $3,%edi
  868         rep
  869         movsl
  870         cld
  871 
  872         GET_CURPCB(%edx)
  873         popl    PCB_ONFAULT(%edx)
  874         popl    %edi
  875         popl    %esi
  876         xorl    %eax,%eax
  877 #ifdef DDB
  878         leave
  879 #endif
  880         ret
  881         
  882 /*
  883  * bcopy(caddr_t from, caddr_t to, size_t len);
  884  * Copy len bytes.
  885  */
  886 ALTENTRY(ovbcopy)
  887 ENTRY(bcopy)
  888         pushl   %esi
  889         pushl   %edi
  890         movl    12(%esp),%esi
  891         movl    16(%esp),%edi
  892         movl    20(%esp),%ecx
  893         movl    %edi,%eax
  894         subl    %esi,%eax
  895         cmpl    %ecx,%eax               # overlapping?
  896         jb      1f
  897         cld                             # nope, copy forward
  898         shrl    $2,%ecx                 # copy by 32-bit words
  899         rep
  900         movsl
  901         movl    20(%esp),%ecx
  902         andl    $3,%ecx                 # any bytes left?
  903         rep
  904         movsb
  905         popl    %edi
  906         popl    %esi
  907         ret
  908 
  909         ALIGN_TEXT
  910 1:      addl    %ecx,%edi               # copy backward
  911         addl    %ecx,%esi
  912         std
  913         andl    $3,%ecx                 # any fractional bytes?
  914         decl    %edi
  915         decl    %esi
  916         rep
  917         movsb
  918         movl    20(%esp),%ecx           # copy remainder by 32-bit words
  919         shrl    $2,%ecx
  920         subl    $3,%esi
  921         subl    $3,%edi
  922         rep
  923         movsl
  924         popl    %edi
  925         popl    %esi
  926         cld
  927         ret
  928 
  929 /*
  930  * Emulate memcpy() by swapping the first two arguments and calling bcopy()
  931  */
  932 ENTRY(memcpy)
  933         movl    4(%esp),%ecx
  934         xchg    8(%esp),%ecx
  935         movl    %ecx,4(%esp)
  936         jmp     _C_LABEL(bcopy)
  937 
  938 /*****************************************************************************/
  939 
  940 /*
  941  * The following primitives are used to copy data in and out of the user's
  942  * address space.
  943  */
  944 
  945 /*
  946  * copyout(caddr_t from, caddr_t to, size_t len);
  947  * Copy len bytes into the user's address space.
  948  */
  949 ENTRY(copyout)
  950 #ifdef DDB
  951         pushl   %ebp
  952         movl    %esp,%ebp
  953 #endif
  954         pushl   %esi
  955         pushl   %edi
  956         pushl   $0      
  957         
  958         movl    16+FPADD(%esp),%esi
  959         movl    20+FPADD(%esp),%edi
  960         movl    24+FPADD(%esp),%eax
  961 
  962         /*
  963          * We check that the end of the destination buffer is not past the end
  964          * of the user's address space.  If it's not, then we only need to
  965          * check that each page is writable.  The 486 will do this for us; the
  966          * 386 will not.  (We assume that pages in user space that are not
  967          * writable by the user are not writable by the kernel either.)
  968          */
  969         movl    %edi,%edx
  970         addl    %eax,%edx
  971         jc      _C_LABEL(copy_fault)
  972         cmpl    $VM_MAXUSER_ADDRESS,%edx
  973         ja      _C_LABEL(copy_fault)
  974 
  975 3:      GET_CURPCB(%edx)
  976         movl    $_C_LABEL(copy_fault),PCB_ONFAULT(%edx)
  977 
  978         /* bcopy(%esi, %edi, %eax); */
  979         cld
  980         movl    %eax,%ecx
  981         shrl    $2,%ecx
  982         rep
  983         movsl
  984         movl    %eax,%ecx
  985         andl    $3,%ecx
  986         rep
  987         movsb
  988 
  989         popl    PCB_ONFAULT(%edx)
  990         popl    %edi
  991         popl    %esi
  992         xorl    %eax,%eax
  993 #ifdef DDB
  994         leave
  995 #endif
  996         ret
  997 
  998 /*
  999  * copyin(caddr_t from, caddr_t to, size_t len);
 1000  * Copy len bytes from the user's address space.
 1001  */
 1002 ENTRY(copyin)
 1003 #ifdef DDB
 1004         pushl   %ebp
 1005         movl    %esp,%ebp
 1006 #endif
 1007         pushl   %esi
 1008         pushl   %edi
 1009         GET_CURPCB(%eax)
 1010         pushl   $0
 1011         movl    $_C_LABEL(copy_fault),PCB_ONFAULT(%eax)
 1012         
 1013         movl    16+FPADD(%esp),%esi
 1014         movl    20+FPADD(%esp),%edi
 1015         movl    24+FPADD(%esp),%eax
 1016 
 1017         /*
 1018          * We check that the end of the destination buffer is not past the end
 1019          * of the user's address space.  If it's not, then we only need to
 1020          * check that each page is readable, and the CPU will do that for us.
 1021          */
 1022         movl    %esi,%edx
 1023         addl    %eax,%edx
 1024         jc      _C_LABEL(copy_fault)
 1025         cmpl    $VM_MAXUSER_ADDRESS,%edx
 1026         ja      _C_LABEL(copy_fault)
 1027 
 1028 3:      /* bcopy(%esi, %edi, %eax); */
 1029         cld
 1030         movl    %eax,%ecx
 1031         shrl    $2,%ecx
 1032         rep
 1033         movsl
 1034         movb    %al,%cl
 1035         andb    $3,%cl
 1036         rep
 1037         movsb
 1038 
 1039         GET_CURPCB(%edx)
 1040         popl    PCB_ONFAULT(%edx)
 1041         popl    %edi
 1042         popl    %esi
 1043         xorl    %eax,%eax
 1044 #ifdef DDB
 1045         leave
 1046 #endif
 1047         ret
 1048 
 1049 ENTRY(copy_fault)
 1050         GET_CURPCB(%edx)
 1051         popl    PCB_ONFAULT(%edx)
 1052         popl    %edi
 1053         popl    %esi
 1054         movl    $EFAULT,%eax
 1055 #ifdef DDB
 1056         leave
 1057 #endif
 1058         ret
 1059 
 1060 /*
 1061  * copyoutstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
 1062  * Copy a NUL-terminated string, at most maxlen characters long, into the
 1063  * user's address space.  Return the number of characters copied (including the
 1064  * NUL) in *lencopied.  If the string is too long, return ENAMETOOLONG; else
 1065  * return 0 or EFAULT.
 1066  */
 1067 ENTRY(copyoutstr)
 1068 #ifdef DDB
 1069         pushl   %ebp
 1070         movl    %esp,%ebp
 1071 #endif
 1072         pushl   %esi
 1073         pushl   %edi
 1074 
 1075         movl    12+FPADD(%esp),%esi             # esi = from
 1076         movl    16+FPADD(%esp),%edi             # edi = to
 1077         movl    20+FPADD(%esp),%edx             # edx = maxlen
 1078 
 1079 5:      GET_CURPCB(%eax)
 1080         movl    $_C_LABEL(copystr_fault),PCB_ONFAULT(%eax)
 1081         /*
 1082          * Get min(%edx, VM_MAXUSER_ADDRESS-%edi).
 1083          */
 1084         movl    $VM_MAXUSER_ADDRESS,%eax
 1085         subl    %edi,%eax
 1086         jbe     _C_LABEL(copystr_fault)         # die if CF == 1 || ZF == 1
 1087                                                 # i.e. make sure that %edi
 1088                                                 # is below VM_MAXUSER_ADDRESS
 1089 
 1090         cmpl    %edx,%eax
 1091         jae     1f
 1092         movl    %eax,%edx
 1093         movl    %eax,20+FPADD(%esp)
 1094 
 1095 1:      incl    %edx
 1096         cld
 1097 
 1098 1:      decl    %edx
 1099         jz      2f
 1100         lodsb
 1101         stosb
 1102         testb   %al,%al
 1103         jnz     1b
 1104 
 1105         /* Success -- 0 byte reached. */
 1106         decl    %edx
 1107         xorl    %eax,%eax
 1108         jmp     copystr_return
 1109 
 1110 2:      /* edx is zero -- return EFAULT or ENAMETOOLONG. */
 1111         cmpl    $VM_MAXUSER_ADDRESS,%edi
 1112         jae     _C_LABEL(copystr_fault)
 1113         movl    $ENAMETOOLONG,%eax
 1114         jmp     copystr_return
 1115 
 1116 /*
 1117  * copyinstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
 1118  * Copy a NUL-terminated string, at most maxlen characters long, from the
 1119  * user's address space.  Return the number of characters copied (including the
 1120  * NUL) in *lencopied.  If the string is too long, return ENAMETOOLONG; else
 1121  * return 0 or EFAULT.
 1122  */
 1123 ENTRY(copyinstr)
 1124 #ifdef DDB
 1125         pushl   %ebp
 1126         movl    %esp,%ebp
 1127 #endif
 1128         pushl   %esi
 1129         pushl   %edi
 1130         GET_CURPCB(%ecx)
 1131         movl    $_C_LABEL(copystr_fault),PCB_ONFAULT(%ecx)
 1132 
 1133         movl    12+FPADD(%esp),%esi             # %esi = from
 1134         movl    16+FPADD(%esp),%edi             # %edi = to
 1135         movl    20+FPADD(%esp),%edx             # %edx = maxlen
 1136 
 1137         /*
 1138          * Get min(%edx, VM_MAXUSER_ADDRESS-%esi).
 1139          */
 1140         movl    $VM_MAXUSER_ADDRESS,%eax
 1141         subl    %esi,%eax
 1142         jbe     _C_LABEL(copystr_fault)         # Error if CF == 1 || ZF == 1
 1143                                                 # i.e. make sure that %esi
 1144                                                 # is below VM_MAXUSER_ADDRESS
 1145         cmpl    %edx,%eax
 1146         jae     1f
 1147         movl    %eax,%edx
 1148         movl    %eax,20+FPADD(%esp)
 1149 
 1150 1:      incl    %edx
 1151         cld
 1152 
 1153 1:      decl    %edx
 1154         jz      2f
 1155         lodsb
 1156         stosb
 1157         testb   %al,%al
 1158         jnz     1b
 1159 
 1160         /* Success -- 0 byte reached. */
 1161         decl    %edx
 1162         xorl    %eax,%eax
 1163         jmp     copystr_return
 1164 
 1165 2:      /* edx is zero -- return EFAULT or ENAMETOOLONG. */
 1166         cmpl    $VM_MAXUSER_ADDRESS,%esi
 1167         jae     _C_LABEL(copystr_fault)
 1168         movl    $ENAMETOOLONG,%eax
 1169         jmp     copystr_return
 1170 
 1171 ENTRY(copystr_fault)
 1172         movl    $EFAULT,%eax
 1173 
 1174 copystr_return:
 1175         /* Set *lencopied and return %eax. */
 1176         GET_CURPCB(%ecx)
 1177         movl    $0,PCB_ONFAULT(%ecx)
 1178         movl    20+FPADD(%esp),%ecx
 1179         subl    %edx,%ecx
 1180         movl    24+FPADD(%esp),%edx
 1181         testl   %edx,%edx
 1182         jz      8f
 1183         movl    %ecx,(%edx)
 1184 
 1185 8:      popl    %edi
 1186         popl    %esi
 1187 #ifdef DDB
 1188         leave
 1189 #endif
 1190         ret
 1191 
 1192 /*
 1193  * copystr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
 1194  * Copy a NUL-terminated string, at most maxlen characters long.  Return the
 1195  * number of characters copied (including the NUL) in *lencopied.  If the
 1196  * string is too long, return ENAMETOOLONG; else return 0.
 1197  */
 1198 ENTRY(copystr)
 1199 #ifdef DDB
 1200         pushl   %ebp
 1201         movl    %esp,%ebp
 1202 #endif
 1203         pushl   %esi
 1204         pushl   %edi
 1205 
 1206         movl    12+FPADD(%esp),%esi             # esi = from
 1207         movl    16+FPADD(%esp),%edi             # edi = to
 1208         movl    20+FPADD(%esp),%edx             # edx = maxlen
 1209         incl    %edx
 1210         cld
 1211 
 1212 1:      decl    %edx
 1213         jz      4f
 1214         lodsb
 1215         stosb
 1216         testb   %al,%al
 1217         jnz     1b
 1218 
 1219         /* Success -- 0 byte reached. */
 1220         decl    %edx
 1221         xorl    %eax,%eax
 1222         jmp     6f
 1223 
 1224 4:      /* edx is zero -- return ENAMETOOLONG. */
 1225         movl    $ENAMETOOLONG,%eax
 1226 
 1227 6:      /* Set *lencopied and return %eax. */
 1228         movl    20+FPADD(%esp),%ecx
 1229         subl    %edx,%ecx
 1230         movl    24+FPADD(%esp),%edx
 1231         testl   %edx,%edx
 1232         jz      7f
 1233         movl    %ecx,(%edx)
 1234 
 1235 7:      popl    %edi
 1236         popl    %esi
 1237 #ifdef DDB
 1238         leave
 1239 #endif
 1240         ret
 1241 
 1242 /*****************************************************************************/
 1243 
 1244 /*
 1245  * The following is i386-specific nonsense.
 1246  */
 1247 
 1248 /*
 1249  * void lgdt(struct region_descriptor *rdp);
 1250  * Change the global descriptor table.
 1251  */
 1252 NENTRY(lgdt)
 1253         /* Reload the descriptor table. */
 1254         movl    4(%esp),%eax
 1255         lgdt    (%eax)
 1256         /* Flush the prefetch q. */
 1257         jmp     1f
 1258         nop
 1259 1:      /* Reload "stale" selectors. */
 1260         movl    $GSEL(GDATA_SEL, SEL_KPL),%eax
 1261         movw    %ax,%ds
 1262         movw    %ax,%es
 1263         movw    %ax,%ss
 1264         movl    $GSEL(GCPU_SEL, SEL_KPL),%eax
 1265         movw    %ax,%fs
 1266         /* Reload code selector by doing intersegment return. */
 1267         popl    %eax
 1268         pushl   $GSEL(GCODE_SEL, SEL_KPL)
 1269         pushl   %eax
 1270         lret
 1271 
 1272 ENTRY(setjmp)
 1273         movl    4(%esp),%eax
 1274         movl    %ebx,(%eax)             # save ebx
 1275         movl    %esp,4(%eax)            # save esp
 1276         movl    %ebp,8(%eax)            # save ebp
 1277         movl    %esi,12(%eax)           # save esi
 1278         movl    %edi,16(%eax)           # save edi
 1279         movl    (%esp),%edx             # get rta
 1280         movl    %edx,20(%eax)           # save eip
 1281         xorl    %eax,%eax               # return (0);
 1282         ret
 1283 
 1284 ENTRY(longjmp)
 1285         movl    4(%esp),%eax
 1286         movl    (%eax),%ebx             # restore ebx
 1287         movl    4(%eax),%esp            # restore esp
 1288         movl    8(%eax),%ebp            # restore ebp
 1289         movl    12(%eax),%esi           # restore esi
 1290         movl    16(%eax),%edi           # restore edi
 1291         movl    20(%eax),%edx           # get rta
 1292         movl    %edx,(%esp)             # put in return frame
 1293         xorl    %eax,%eax               # return (1);
 1294         incl    %eax
 1295         ret
 1296 
 1297 /*****************************************************************************/
 1298 
 1299 /*
 1300  * The following primitives manipulate the run queues.
 1301  * whichqs tells which of the 32 queues qs have processes in them.
 1302  * Setrq puts processes into queues, Remrq removes them from queues.
 1303  * The running process is on no queue, other processes are on a queue
 1304  * related to p->p_pri, divided by 4 actually to shrink the 0-127 range
 1305  * of priorities into the 32 available queues.
 1306  */
 1307         .globl  _C_LABEL(whichqs),_C_LABEL(qs),_C_LABEL(uvmexp),_C_LABEL(panic)
 1308 /*
 1309  * setrunqueue(struct proc *p);
 1310  * Insert a process on the appropriate queue.  Should be called at splclock().
 1311  */
 1312 NENTRY(setrunqueue)
 1313         movl    4(%esp),%eax
 1314 #ifdef DIAGNOSTIC
 1315         cmpl    $0,P_BACK(%eax) # should not be on q already
 1316         jne     1f
 1317         cmpl    $0,P_WCHAN(%eax)
 1318         jne     1f
 1319         cmpb    $SRUN,P_STAT(%eax)
 1320         jne     1f
 1321 #endif /* DIAGNOSTIC */
 1322         movzbl  P_PRIORITY(%eax),%edx
 1323         shrl    $2,%edx
 1324         btsl    %edx,_C_LABEL(whichqs)          # set q full bit
 1325         leal    _C_LABEL(qs)(,%edx,8),%edx      # locate q hdr
 1326         movl    P_BACK(%edx),%ecx
 1327         movl    %edx,P_FORW(%eax)       # link process on tail of q
 1328         movl    %eax,P_BACK(%edx)
 1329         movl    %eax,P_FORW(%ecx)
 1330         movl    %ecx,P_BACK(%eax)
 1331         ret
 1332 #ifdef DIAGNOSTIC
 1333 1:      pushl   $2f
 1334         call    _C_LABEL(panic)
 1335         /* NOTREACHED */
 1336 2:      .asciz  "setrunqueue"
 1337 #endif /* DIAGNOSTIC */
 1338 
 1339 /*
 1340  * remrunqueue(struct proc *p);
 1341  * Remove a process from its queue.  Should be called at splclock().
 1342  */
 1343 NENTRY(remrunqueue)
 1344         movl    4(%esp),%ecx
 1345         movzbl  P_PRIORITY(%ecx),%eax
 1346 #ifdef DIAGNOSTIC
 1347         shrl    $2,%eax
 1348         btl     %eax,_C_LABEL(whichqs)
 1349         jnc     1f
 1350 #endif /* DIAGNOSTIC */
 1351         movl    P_BACK(%ecx),%edx       # unlink process
 1352         movl    $0,P_BACK(%ecx)         # zap reverse link to indicate off list
 1353         movl    P_FORW(%ecx),%ecx
 1354         movl    %ecx,P_FORW(%edx)
 1355         movl    %edx,P_BACK(%ecx)
 1356         cmpl    %ecx,%edx               # q still has something?
 1357         jne     2f
 1358 #ifndef DIAGNOSTIC
 1359         shrl    $2,%eax
 1360 #endif
 1361         btrl    %eax,_C_LABEL(whichqs)          # no; clear bit
 1362 2:      ret
 1363 #ifdef DIAGNOSTIC
 1364 1:      pushl   $3f
 1365         call    _C_LABEL(panic)
 1366         /* NOTREACHED */
 1367 3:      .asciz  "remrunqueue"
 1368 #endif /* DIAGNOSTIC */
 1369 
 1370 #if NAPM > 0
 1371         .globl _C_LABEL(apm_cpu_idle),_C_LABEL(apm_cpu_busy)
 1372 #endif
 1373 /*
 1374  * When no processes are on the runq, cpu_switch() branches to here to wait for
 1375  * something to come ready.
 1376  */
 1377 ENTRY(idle)
 1378         /* Skip context saving if we have none. */
 1379         testl %esi,%esi
 1380         jz      1f
 1381 
 1382         /*
 1383          * idling:      save old context.
 1384          *
 1385          * Registers:
 1386          *   %eax, %ebx, %ecx - scratch
 1387          *   %esi - old proc, then old pcb
 1388          *   %edi - idle pcb
 1389          *   %edx - idle TSS selector
 1390          */
 1391 
 1392         pushl   %esi
 1393         call    _C_LABEL(pmap_deactivate)       # pmap_deactivate(oldproc)
 1394         addl    $4,%esp
 1395 
 1396         movl    P_ADDR(%esi),%esi
 1397 
 1398         /* Save stack pointers. */
 1399         movl    %esp,PCB_ESP(%esi)
 1400         movl    %ebp,PCB_EBP(%esi)
 1401 
 1402         /* Find idle PCB for this CPU */
 1403 #ifndef MULTIPROCESSOR
 1404         movl    $_C_LABEL(proc0),%ebx
 1405         movl    P_ADDR(%ebx),%edi
 1406         movl    P_MD_TSS_SEL(%ebx),%edx
 1407 #else
 1408         movl    CPUVAR(IDLE_PCB), %edi
 1409         movl    CPUVAR(IDLE_TSS_SEL), %edx
 1410 #endif
 1411 
 1412         /* Restore the idle context (avoid interrupts) */
 1413         cli
 1414 
 1415         /* Restore stack pointers. */
 1416         movl    PCB_ESP(%edi),%esp
 1417         movl    PCB_EBP(%edi),%ebp
 1418 
 1419 
 1420         /* Switch address space. */
 1421         movl    PCB_CR3(%edi),%ecx
 1422         movl    %ecx,%cr3
 1423 
 1424         /* Switch TSS. Reset "task busy" flag before loading. */
 1425         movl    CPUVAR(GDT), %eax
 1426         andl    $~0x0200,4-SEL_KPL(%eax,%edx,1)
 1427         ltr     %dx
 1428 
 1429         /* We're always in the kernel, so we don't need the LDT. */
 1430 
 1431         /* Restore cr0 (including FPU state). */
 1432         movl    PCB_CR0(%edi),%ecx
 1433         movl    %ecx,%cr0
 1434 
 1435         /* Record new pcb. */
 1436         SET_CURPCB(%edi)
 1437 
 1438         xorl    %esi,%esi
 1439         sti
 1440 
 1441 1:
 1442 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)       
 1443         call    _C_LABEL(sched_unlock_idle)
 1444 #endif
 1445 
 1446         movl    $IPL_NONE,CPL           # spl0()
 1447         call    _C_LABEL(Xspllower)     # process pending interrupts
 1448         jmp     _C_LABEL(idle_start)
 1449 
 1450 ENTRY(idle_loop)
 1451 #if NAPM > 0
 1452         call    _C_LABEL(apm_cpu_idle)
 1453 #else
 1454 #if NPCTR > 0
 1455         addl    $1,_C_LABEL(pctr_idlcnt)
 1456         adcl    $0,_C_LABEL(pctr_idlcnt)+4
 1457 #endif
 1458         sti
 1459         hlt
 1460 #endif
 1461 ENTRY(idle_start)
 1462         cli
 1463         cmpl    $0,_C_LABEL(whichqs)
 1464         jz      _C_LABEL(idle_loop)
 1465 
 1466 ENTRY(idle_exit)
 1467         movl    $IPL_HIGH,CPL           # splhigh
 1468         sti
 1469 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)       
 1470         call    _C_LABEL(sched_lock_idle)
 1471 #endif
 1472 #if NAPM > 0
 1473         call    _C_LABEL(apm_cpu_busy)
 1474 #endif
 1475         jmp     switch_search
 1476                 
 1477 #ifdef DIAGNOSTIC
 1478 NENTRY(switch_error)
 1479         pushl   $1f
 1480         call    _C_LABEL(panic)
 1481         /* NOTREACHED */
 1482 1:      .asciz  "cpu_switch"
 1483 #endif /* DIAGNOSTIC */
 1484 
 1485 /*
 1486  * cpu_switch(void);
 1487  * Find a runnable process and switch to it.  Wait if necessary.  If the new
 1488  * process is the same as the old one, we short-circuit the context save and
 1489  * restore.
 1490  */
 1491 ENTRY(cpu_switch)
 1492         pushl   %ebx
 1493         pushl   %esi
 1494         pushl   %edi
 1495         pushl   CPL
 1496 
 1497         movl    CPUVAR(CURPROC), %esi
 1498 
 1499         /*
 1500          * Clear curproc so that we don't accumulate system time while idle.
 1501          * This also insures that schedcpu() will move the old process to
 1502          * the correct queue if it happens to get called from the spllower()
 1503          * below and changes the priority.  (See corresponding comment in
 1504          * userret()).
 1505          */
 1506         movl    $0, CPUVAR(CURPROC)
 1507 
 1508 switch_search:
 1509         /*
 1510          * First phase: find new process.
 1511          *
 1512          * Registers:
 1513          *   %eax - queue head, scratch, then zero
 1514          *   %ebx - queue number
 1515          *   %ecx - cached value of whichqs
 1516          *   %edx - next process in queue
 1517          *   %esi - old process
 1518          *   %edi - new process
 1519          */
 1520 
 1521         /* Wait for new process. */
 1522         movl    _C_LABEL(whichqs),%ecx
 1523         bsfl    %ecx,%ebx               # find a full q
 1524         jz      _C_LABEL(idle)          # if none, idle
 1525         leal    _C_LABEL(qs)(,%ebx,8),%eax      # select q
 1526         movl    P_FORW(%eax),%edi       # unlink from front of process q
 1527 #ifdef  DIAGNOSTIC
 1528         cmpl    %edi,%eax               # linked to self (i.e. nothing queued)?
 1529         je      _C_LABEL(switch_error)  # not possible
 1530 #endif /* DIAGNOSTIC */
 1531         movl    P_FORW(%edi),%edx
 1532         movl    %edx,P_FORW(%eax)
 1533         movl    %eax,P_BACK(%edx)
 1534 
 1535         cmpl    %edx,%eax               # q empty?
 1536         jne     3f
 1537 
 1538         btrl    %ebx,%ecx               # yes, clear to indicate empty
 1539         movl    %ecx,_C_LABEL(whichqs)  # update q status
 1540 
 1541 3:      xorl    %eax, %eax
 1542         /* We just did it. */
 1543         movl    $0, CPUVAR(RESCHED)
 1544 
 1545 #ifdef  DIAGNOSTIC
 1546         cmpl    %eax,P_WCHAN(%edi)      # Waiting for something?
 1547         jne     _C_LABEL(switch_error)  # Yes; shouldn't be queued.
 1548         cmpb    $SRUN,P_STAT(%edi)      # In run state?
 1549         jne     _C_LABEL(switch_error)  # No; shouldn't be queued.
 1550 #endif /* DIAGNOSTIC */
 1551 
 1552         /* Isolate process.  XXX Is this necessary? */
 1553         movl    %eax,P_BACK(%edi)
 1554 
 1555         /* Record new process. */
 1556         movb    $SONPROC,P_STAT(%edi)   # p->p_stat = SONPROC
 1557         movl    CPUVAR(SELF), %ecx
 1558         movl    %edi, CPUVAR(CURPROC)
 1559         movl    %ecx, P_CPU(%edi)
 1560 
 1561         /* Skip context switch if same process. */
 1562         cmpl    %edi,%esi
 1563         je      switch_return
 1564 
 1565         /* If old process exited, don't bother. */
 1566         testl   %esi,%esi
 1567         jz      switch_exited
 1568 
 1569         /*
 1570          * Second phase: save old context.
 1571          *
 1572          * Registers:
 1573          *   %eax, %ecx - scratch
 1574          *   %esi - old process, then old pcb
 1575          *   %edi - new process
 1576          */
 1577 
 1578         pushl   %esi
 1579         call    _C_LABEL(pmap_deactivate)
 1580         addl    $4,%esp
 1581 
 1582         movl    P_ADDR(%esi),%esi
 1583 
 1584         /* Save stack pointers. */
 1585         movl    %esp,PCB_ESP(%esi)
 1586         movl    %ebp,PCB_EBP(%esi)
 1587 
 1588 switch_exited:
 1589         /*
 1590          * Third phase: restore saved context.
 1591          *
 1592          * Registers:
 1593          *   %eax, %ecx, %edx - scratch
 1594          *   %esi - new pcb
 1595          *   %edi - new process
 1596          */
 1597 
 1598         /* No interrupts while loading new state. */
 1599         cli
 1600         movl    P_ADDR(%edi),%esi
 1601 
 1602         /* Restore stack pointers. */
 1603         movl    PCB_ESP(%esi),%esp
 1604         movl    PCB_EBP(%esi),%ebp
 1605 
 1606 #if 0
 1607         /* Don't bother with the rest if switching to a system process. */
 1608         testl   $P_SYSTEM,P_FLAG(%edi)
 1609         jnz     switch_restored
 1610 #endif
 1611 
 1612         /*
 1613          * Activate the address space.  We're curproc, so %cr3 will
 1614          * be reloaded, but we're not yet curpcb, so the LDT won't
 1615          * be reloaded, although the PCB copy of the selector will
 1616          * be refreshed from the pmap.
 1617          */
 1618         pushl   %edi
 1619         call    _C_LABEL(pmap_activate)
 1620         addl    $4,%esp
 1621         
 1622         /* Load TSS info. */
 1623         movl    CPUVAR(GDT),%eax
 1624         movl    P_MD_TSS_SEL(%edi),%edx
 1625 
 1626         /* Switch TSS. */
 1627         andl    $~0x0200,4-SEL_KPL(%eax,%edx,1)
 1628         ltr     %dx
 1629 
 1630 #ifdef USER_LDT
 1631         /*
 1632          * Switch LDT.
 1633          *
 1634          * XXX
 1635          * Always do this, because the LDT could have been swapped into a
 1636          * different selector after a process exited.  (See gdt_compact().)
 1637          */
 1638         movl    PCB_LDT_SEL(%esi),%edx
 1639         lldt    %dx
 1640 #endif /* USER_LDT */
 1641 
 1642 switch_restored:
 1643         /* Restore cr0 (including FPU state). */
 1644         movl    PCB_CR0(%esi),%ecx
 1645 #ifdef MULTIPROCESSOR
 1646         /*
 1647          * If our floating point registers are on a different CPU,
 1648          * clear CR0_TS so we'll trap rather than reuse bogus state.
 1649          */
 1650         movl    CPUVAR(SELF), %ebx
 1651         cmpl    PCB_FPCPU(%esi),%ebx
 1652         jz      1f
 1653         orl     $CR0_TS,%ecx
 1654 1:      
 1655 #endif  
 1656         movl    %ecx,%cr0
 1657 
 1658         /* Record new pcb. */
 1659         SET_CURPCB(%esi)
 1660 
 1661         /* Interrupts are okay again. */
 1662         sti
 1663 
 1664 switch_return:
 1665 #if 0
 1666         pushl   %edi
 1667         movl    CPUVAR(NAME), %ebx
 1668         leal    CPU_INFO_NAME(%ebx),%ebx
 1669         pushl   %ebx
 1670         pushl   $1f
 1671         call    _C_LABEL(printf)
 1672         addl    $0xc,%esp
 1673 #endif
 1674 #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
 1675         call    _C_LABEL(sched_unlock_idle)
 1676 #endif
 1677         /*
 1678          * Restore old cpl from stack.  Note that this is always an increase,
 1679          * due to the spl0() on entry.
 1680          */
 1681         popl    CPL
 1682 
 1683         movl    %edi,%eax               # return (p);
 1684         popl    %edi
 1685         popl    %esi
 1686         popl    %ebx
 1687         ret
 1688 1:      .asciz  "%s: scheduled %x\n"
 1689 /*
 1690  * switch_exit(struct proc *p);
 1691  * Switch to the appropriate idle context (proc0's if uniprocessor; the cpu's if
 1692  * multiprocessor) and deallocate the address space and kernel stack for p.
 1693  * Then jump into cpu_switch(), as if we were in the idle proc all along.
 1694  */
 1695 #ifndef MULTIPROCESSOR
 1696         .globl  _C_LABEL(proc0)
 1697 #endif
 1698 ENTRY(switch_exit)
 1699         movl    4(%esp),%edi            # old process
 1700 #ifndef MULTIPROCESSOR
 1701         movl    $_C_LABEL(proc0),%ebx
 1702         movl    P_ADDR(%ebx),%esi
 1703         movl    P_MD_TSS_SEL(%ebx),%edx
 1704 #else
 1705         movl    CPUVAR(IDLE_PCB), %esi
 1706         movl    CPUVAR(IDLE_TSS_SEL), %edx
 1707 #endif
 1708 
 1709         /* In case we fault... */
 1710         movl    $0, CPUVAR(CURPROC)
 1711 
 1712         /* Restore the idle context. */
 1713         cli
 1714 
 1715         /* Restore stack pointers. */
 1716         movl    PCB_ESP(%esi),%esp
 1717         movl    PCB_EBP(%esi),%ebp
 1718 
 1719         /* Load TSS info. */
 1720         movl    CPUVAR(GDT), %eax
 1721 
 1722         /* Switch address space. */
 1723         movl    PCB_CR3(%esi),%ecx
 1724         movl    %ecx,%cr3
 1725 
 1726         /* Switch TSS. */
 1727         andl    $~0x0200,4-SEL_KPL(%eax,%edx,1)
 1728         ltr     %dx
 1729 
 1730         /* We're always in the kernel, so we don't need the LDT. */
 1731 
 1732         /* Clear segment registers; always null in proc0. */
 1733         xorl    %ecx,%ecx
 1734         movw    %cx,%gs
 1735 
 1736         /* Point to cpu_info */
 1737         movl    $GSEL(GCPU_SEL, SEL_KPL),%ecx
 1738         movw    %cx,%fs
 1739 
 1740         /* Restore cr0 (including FPU state). */
 1741         movl    PCB_CR0(%esi),%ecx
 1742         movl    %ecx,%cr0
 1743 
 1744         /* Record new pcb. */
 1745         SET_CURPCB(%esi)
 1746 
 1747         /* Interrupts are okay again. */
 1748         sti
 1749 
 1750         /*
 1751          * Schedule the dead process's vmspace and stack to be freed.
 1752          */
 1753         pushl   %edi                    /* exit2(p) */
 1754         call    _C_LABEL(exit2)
 1755         addl    $4,%esp
 1756 
 1757         /* Jump into cpu_switch() with the right state. */
 1758         xorl    %esi,%esi
 1759         movl    $0, CPUVAR(CURPROC)
 1760         jmp     switch_search
 1761 
 1762 /*
 1763  * savectx(struct pcb *pcb);
 1764  * Update pcb, saving current processor state.
 1765  */
 1766 ENTRY(savectx)
 1767         movl    4(%esp),%edx            # edx = p->p_addr
 1768 
 1769         /* Save stack pointers. */
 1770         movl    %esp,PCB_ESP(%edx)
 1771         movl    %ebp,PCB_EBP(%edx)
 1772 
 1773         ret
 1774 
 1775 /*****************************************************************************/
 1776 
 1777 /*
 1778  * Trap and fault vector routines
 1779  *
 1780  * On exit from the kernel to user mode, we always need to check for ASTs.  In
 1781  * addition, we need to do this atomically; otherwise an interrupt may occur
 1782  * which causes an AST, but it won't get processed until the next kernel entry
 1783  * (possibly the next clock tick).  Thus, we disable interrupt before checking,
 1784  * and only enable them again on the final `iret' or before calling the AST
 1785  * handler.
 1786  *
 1787  * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose
 1788  * control.  The sti's give the standard losing behaviour for ddb and kgdb.
 1789  */
 1790 #define IDTVEC(name)    ALIGN_TEXT; .globl X/**/name; X/**/name:
 1791 
 1792 #define TRAP(a)         pushl $(a) ; jmp _C_LABEL(alltraps)
 1793 #define ZTRAP(a)        pushl $0 ; TRAP(a)
 1794 #define BPTTRAP(a)      testb $(PSL_I>>8),13(%esp) ; jz 1f ; sti ; 1: ; \
 1795                         TRAP(a)
 1796 
 1797         .text
 1798 IDTVEC(div)
 1799         ZTRAP(T_DIVIDE)
 1800 IDTVEC(dbg)
 1801         subl    $4,%esp
 1802         pushl   %eax
 1803         movl    %dr6,%eax
 1804         movl    %eax,4(%esp)
 1805         andb    $~0xf,%al
 1806         movl    %eax,%dr6
 1807         popl    %eax
 1808         BPTTRAP(T_TRCTRAP)
 1809 IDTVEC(nmi)
 1810         ZTRAP(T_NMI)
 1811 IDTVEC(bpt)
 1812         pushl   $0
 1813         BPTTRAP(T_BPTFLT)
 1814 IDTVEC(ofl)
 1815         ZTRAP(T_OFLOW)
 1816 IDTVEC(bnd)
 1817         ZTRAP(T_BOUND)
 1818 IDTVEC(ill)
 1819         ZTRAP(T_PRIVINFLT)
 1820 IDTVEC(dna)
 1821 #if NNPX > 0
 1822         pushl   $0                      # dummy error code
 1823         pushl   $T_DNA
 1824         INTRENTRY
 1825 #ifdef MULTIPROCESSOR
 1826         pushl   CPUVAR(SELF)
 1827 #else
 1828         pushl   $_C_LABEL(cpu_info_primary)
 1829 #endif
 1830         call    *_C_LABEL(npxdna_func)
 1831         addl    $4,%esp
 1832         testl   %eax,%eax
 1833         jz      calltrap
 1834         INTRFASTEXIT
 1835 #else
 1836         ZTRAP(T_DNA)
 1837 #endif
 1838 IDTVEC(dble)
 1839         TRAP(T_DOUBLEFLT)
 1840 IDTVEC(fpusegm)
 1841         ZTRAP(T_FPOPFLT)
 1842 IDTVEC(tss)
 1843         TRAP(T_TSSFLT)
 1844 IDTVEC(missing)
 1845         TRAP(T_SEGNPFLT)
 1846 IDTVEC(stk)
 1847         TRAP(T_STKFLT)
 1848 IDTVEC(prot)
 1849         TRAP(T_PROTFLT)
 1850 #ifdef I586_CPU
 1851 IDTVEC(f00f_redirect)
 1852         pushl   $T_PAGEFLT
 1853         INTRENTRY
 1854         testb   $PGEX_U,TF_ERR(%esp)
 1855         jnz     calltrap
 1856         movl    %cr2,%eax
 1857         subl    _C_LABEL(idt),%eax
 1858         cmpl    $(6*8),%eax
 1859         jne     calltrap
 1860         movb    $T_PRIVINFLT,TF_TRAPNO(%esp)
 1861         jmp     calltrap
 1862 #endif
 1863 IDTVEC(page)
 1864         TRAP(T_PAGEFLT)
 1865 IDTVEC(rsvd)
 1866         ZTRAP(T_RESERVED)
 1867 IDTVEC(mchk)
 1868         ZTRAP(T_MACHK)
 1869 IDTVEC(simd)
 1870         ZTRAP(T_XFTRAP)
 1871 IDTVEC(intrspurious)
 1872         /*
 1873          * The Pentium Pro local APIC may erroneously call this vector for a
 1874          * default IR7.  Just ignore it.
 1875          *
 1876          * (The local APIC does this when CPL is raised while it's on the
 1877          * way to delivering an interrupt.. presumably enough has been set
 1878          * up that it's inconvenient to abort delivery completely..)
 1879          */
 1880         iret
 1881 IDTVEC(fpu)
 1882 #if NNPX > 0
 1883         /*
 1884          * Handle like an interrupt so that we can call npxintr to clear the
 1885          * error.  It would be better to handle npx interrupts as traps but
 1886          * this is difficult for nested interrupts.
 1887          */
 1888         pushl   $0                      # dummy error code
 1889         pushl   $T_ASTFLT
 1890         INTRENTRY
 1891         pushl   CPL                     # if_ppl in intrframe
 1892         pushl   %esp                    # push address of intrframe
 1893         incl    _C_LABEL(uvmexp)+V_TRAP
 1894         call    _C_LABEL(npxintr)
 1895         addl    $8,%esp                 # pop address and if_ppl
 1896         INTRFASTEXIT
 1897 #else
 1898         ZTRAP(T_ARITHTRAP)
 1899 #endif
 1900 IDTVEC(align)
 1901         ZTRAP(T_ALIGNFLT)
 1902         /* 18 - 31 reserved for future exp */
 1903 
 1904 /*
 1905  * If an error is detected during trap, syscall, or interrupt exit, trap() will
 1906  * change %eip to point to one of these labels.  We clean up the stack, if
 1907  * necessary, and resume as if we were handling a general protection fault.
 1908  * This will cause the process to get a SIGBUS.
 1909  */
 1910 NENTRY(resume_iret)
 1911         ZTRAP(T_PROTFLT)
 1912 NENTRY(resume_pop_ds)
 1913         pushl   %es
 1914         movl    $GSEL(GDATA_SEL, SEL_KPL),%eax
 1915         movw    %ax,%es
 1916 NENTRY(resume_pop_es)
 1917         pushl   %gs
 1918         movl    $GSEL(GDATA_SEL, SEL_KPL),%eax
 1919         movw    %ax,%gs
 1920 NENTRY(resume_pop_gs)
 1921         pushl   %fs
 1922         movl    $GSEL(GCPU_SEL, SEL_KPL),%eax
 1923         movw    %ax,%fs
 1924 NENTRY(resume_pop_fs)
 1925         movl    $T_PROTFLT,TF_TRAPNO(%esp)
 1926         jmp     calltrap
 1927 
 1928 NENTRY(alltraps)
 1929         INTRENTRY
 1930 calltrap:
 1931 #ifdef DIAGNOSTIC
 1932         movl    CPL,%ebx
 1933 #endif /* DIAGNOSTIC */
 1934         call    _C_LABEL(trap)
 1935 2:      /* Check for ASTs on exit to user mode. */
 1936         cli
 1937         CHECK_ASTPENDING(%ecx)
 1938         je      1f
 1939         testb   $SEL_RPL,TF_CS(%esp)
 1940 #ifdef VM86
 1941         jnz     5f
 1942         testl   $PSL_VM,TF_EFLAGS(%esp)
 1943 #endif
 1944         jz      1f
 1945 5:      CLEAR_ASTPENDING(%ecx)
 1946         sti
 1947         movl    $T_ASTFLT,TF_TRAPNO(%esp)
 1948         call    _C_LABEL(trap)
 1949         jmp     2b
 1950 #ifndef DIAGNOSTIC
 1951 1:      INTRFASTEXIT
 1952 #else
 1953 1:      cmpl    CPL,%ebx
 1954         jne     3f
 1955         INTRFASTEXIT
 1956 3:      sti
 1957         pushl   $4f
 1958         call    _C_LABEL(printf)
 1959         addl    $4,%esp
 1960 #if defined(DDB) && 0
 1961         int     $3
 1962 #endif /* DDB */
 1963         movl    %ebx,CPL
 1964         jmp     2b
 1965 4:      .asciz  "WARNING: SPL NOT LOWERED ON TRAP EXIT\n"
 1966 #endif /* DIAGNOSTIC */
 1967 
 1968 /*
 1969  * Old call gate entry for syscall
 1970  */
 1971 IDTVEC(osyscall)
 1972         /* Set eflags in trap frame. */
 1973         pushfl
 1974         popl    8(%esp)
 1975         /* Turn off trace flag and nested task. */
 1976         pushfl
 1977         andb    $~((PSL_T|PSL_NT)>>8),1(%esp)
 1978         popfl
 1979         pushl   $7              # size of instruction for restart
 1980         jmp     syscall1
 1981 IDTVEC(osyscall_end)
 1982 
 1983 /*
 1984  * Trap gate entry for syscall
 1985  */
 1986 IDTVEC(syscall)
 1987         pushl   $2              # size of instruction for restart
 1988 syscall1:
 1989         pushl   $T_ASTFLT       # trap # for doing ASTs
 1990         INTRENTRY
 1991         call    _C_LABEL(syscall)
 1992 2:      /* Check for ASTs on exit to user mode. */
 1993         cli
 1994         CHECK_ASTPENDING(%ecx)
 1995         je      1f
 1996         /* Always returning to user mode here. */
 1997         CLEAR_ASTPENDING(%ecx)
 1998         sti
 1999         /* Pushed T_ASTFLT into tf_trapno on entry. */
 2000         call    _C_LABEL(trap)
 2001         jmp     2b
 2002 1:      INTRFASTEXIT
 2003 
 2004 #include <i386/i386/vector.s>
 2005 #include <i386/isa/icu.s>
 2006 
 2007 /*
 2008  * bzero (void *b, size_t len)
 2009  *      write len zero bytes to the string b.
 2010  */
 2011 
 2012 ENTRY(bzero)
 2013         pushl   %edi
 2014         movl    8(%esp),%edi
 2015         movl    12(%esp),%edx
 2016 
 2017         cld                             /* set fill direction forward */
 2018         xorl    %eax,%eax               /* set fill data to 0 */
 2019 
 2020         /*
 2021          * if the string is too short, it's really not worth the overhead
 2022          * of aligning to word boundaries, etc.  So we jump to a plain
 2023          * unaligned set.
 2024          */
 2025         cmpl    $16,%edx
 2026         jb      7f
 2027 
 2028         movl    %edi,%ecx               /* compute misalignment */
 2029         negl    %ecx
 2030         andl    $3,%ecx
 2031         subl    %ecx,%edx
 2032         rep                             /* zero until word aligned */
 2033         stosb
 2034 
 2035 #if defined(I486_CPU)
 2036 #if defined(I586_CPU) || defined(I686_CPU)
 2037         cmpl    $CPUCLASS_486,_C_LABEL(cpu_class)
 2038         jne     8f
 2039 #endif
 2040 
 2041         movl    %edx,%ecx
 2042         shrl    $6,%ecx
 2043         jz      8f
 2044         andl    $63,%edx
 2045 1:      movl    %eax,(%edi)
 2046         movl    %eax,4(%edi)
 2047         movl    %eax,8(%edi)
 2048         movl    %eax,12(%edi)
 2049         movl    %eax,16(%edi)
 2050         movl    %eax,20(%edi)
 2051         movl    %eax,24(%edi)
 2052         movl    %eax,28(%edi)
 2053         movl    %eax,32(%edi)
 2054         movl    %eax,36(%edi)
 2055         movl    %eax,40(%edi)
 2056         movl    %eax,44(%edi)
 2057         movl    %eax,48(%edi)
 2058         movl    %eax,52(%edi)
 2059         movl    %eax,56(%edi)
 2060         movl    %eax,60(%edi)
 2061         addl    $64,%edi
 2062         decl    %ecx
 2063         jnz     1b
 2064 #endif
 2065 
 2066 8:      movl    %edx,%ecx               /* zero by words */
 2067         shrl    $2,%ecx
 2068         andl    $3,%edx
 2069         rep
 2070         stosl
 2071 
 2072 7:      movl    %edx,%ecx               /* zero remainder bytes */
 2073         rep
 2074         stosb
 2075 
 2076         popl    %edi
 2077         ret
 2078 
 2079 #if defined(I686_CPU) && !defined(SMALL_KERNEL)
 2080 ENTRY(sse2_pagezero)
 2081         pushl   %ebx
 2082         movl    8(%esp),%ecx
 2083         movl    %ecx,%eax
 2084         addl    $4096,%eax
 2085         xor     %ebx,%ebx
 2086 1:
 2087         movnti  %ebx,(%ecx)
 2088         addl    $4,%ecx
 2089         cmpl    %ecx,%eax
 2090         jne     1b
 2091         sfence
 2092         popl    %ebx
 2093         ret
 2094 
 2095 ENTRY(i686_pagezero)
 2096         pushl   %edi
 2097         pushl   %ebx
 2098 
 2099         movl    12(%esp), %edi
 2100         movl    $1024, %ecx
 2101         cld
 2102 
 2103         ALIGN_TEXT
 2104 1:
 2105         xorl    %eax, %eax
 2106         repe
 2107         scasl
 2108         jnz     2f
 2109 
 2110         popl    %ebx
 2111         popl    %edi
 2112         ret
 2113 
 2114         ALIGN_TEXT
 2115 
 2116 2:
 2117         incl    %ecx
 2118         subl    $4, %edi
 2119 
 2120         movl    %ecx, %edx
 2121         cmpl    $16, %ecx
 2122 
 2123         jge     3f
 2124 
 2125         movl    %edi, %ebx
 2126         andl    $0x3f, %ebx
 2127         shrl    %ebx
 2128         shrl    %ebx
 2129         movl    $16, %ecx
 2130         subl    %ebx, %ecx
 2131 
 2132 3:
 2133         subl    %ecx, %edx
 2134         rep
 2135         stosl
 2136 
 2137         movl    %edx, %ecx
 2138         testl   %edx, %edx
 2139         jnz     1b
 2140 
 2141         popl    %ebx
 2142         popl    %edi
 2143         ret
 2144 #endif
 2145 
 2146 #if NLAPIC > 0
 2147 #include <i386/i386/apicvec.s>
 2148 #endif
 2149 
 2150 #include <i386/i386/mutex.S>

/* [<][>][^][v][top][bottom][index][help] */