The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/osfmk/i386/start.s

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*
   26  * @OSF_COPYRIGHT@
   27  */
   28 /* 
   29  * Mach Operating System
   30  * Copyright (c) 1991,1990 Carnegie Mellon University
   31  * All Rights Reserved.
   32  * 
   33  * Permission to use, copy, modify and distribute this software and its
   34  * documentation is hereby granted, provided that both the copyright
   35  * notice and this permission notice appear in all copies of the
   36  * software, derivative works or modified versions, and any portions
   37  * thereof, and that both notices appear in supporting documentation.
   38  * 
   39  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   40  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   41  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   42  * 
   43  * Carnegie Mellon requests users of this software to return to
   44  * 
   45  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   46  *  School of Computer Science
   47  *  Carnegie Mellon University
   48  *  Pittsburgh PA 15213-3890
   49  * 
   50  * any improvements or extensions that they make and grant Carnegie Mellon
   51  * the rights to redistribute these changes.
   52  */
   53 /*
   54  */
   55 
   56 #include <platforms.h>
   57 #include <cpus.h>
   58 #include <mach_kdb.h>
   59 
   60 #include <i386/asm.h>
   61 #include <i386/proc_reg.h>
   62 #include <assym.s>
   63 
   64 #if     NCPUS > 1
   65 
   66 #define CX(addr,reg)    addr(,reg,4)
   67 
   68 #else
   69 
   70 #define CPU_NUMBER(reg)
   71 #define CX(addr,reg)    addr
   72 
   73 #endif  /* NCPUS > 1 */
   74 
   75 #include <i386/mp.h>
   76 
   77 /*
   78  * GAS won't handle an intersegment jump with a relocatable offset.
   79  */
   80 #define LJMP(segment,address)   \
   81         .byte   0xea            ;\
   82         .long   address         ;\
   83         .word   segment
   84 
   85 
   86 
   87 #define KVTOPHYS        (-KERNELBASE)
   88 #define KVTOLINEAR      LINEAR_KERNELBASE
   89 
   90 
   91 #define PA(addr)        (addr)+KVTOPHYS
   92 #define VA(addr)        (addr)-KVTOPHYS
   93 
   94         .data
   95         .align  2
   96         .globl  EXT(_kick_buffer_)
   97 EXT(_kick_buffer_):
   98         .long   1
   99         .long   3
  100         .set    .,.+16836
  101 /*
  102  * Interrupt and bootup stack for initial processor.
  103  */
  104         .align  ALIGN
  105         .globl  EXT(intstack)
  106 EXT(intstack):
  107         .set    ., .+INTSTACK_SIZE
  108         .globl  EXT(eintstack)
  109 EXT(eintstack:)
  110 
  111 #if     NCPUS == 1
  112         .globl  EXT(int_stack_high)     /* all interrupt stacks */
  113 EXT(int_stack_high):                    /* must lie below this */
  114         .long   EXT(eintstack)          /* address */
  115 
  116         .globl  EXT(int_stack_top)      /* top of interrupt stack */
  117 EXT(int_stack_top):
  118         .long   EXT(eintstack)
  119 #endif
  120 
  121 #if     MACH_KDB
  122 /*
  123  * Kernel debugger stack for each processor.
  124  */
  125         .align  ALIGN
  126         .globl  EXT(db_stack_store)
  127 EXT(db_stack_store):
  128         .set    ., .+(INTSTACK_SIZE*NCPUS)
  129 
  130 /*
  131  * Stack for last-ditch debugger task for each processor.
  132  */
  133         .align  ALIGN
  134         .globl  EXT(db_task_stack_store)
  135 EXT(db_task_stack_store):
  136         .set    ., .+(INTSTACK_SIZE*NCPUS)
  137 #endif  /* MACH_KDB */
  138 
  139 /*
  140  * per-processor kernel debugger stacks
  141  */
  142         .align  ALIGN
  143         .globl  EXT(kgdb_stack_store)
  144 EXT(kgdb_stack_store):
  145         .set    ., .+(INTSTACK_SIZE*NCPUS)
  146 
  147 
  148 /*
  149  * Pointers to GDT and IDT.  These contain linear addresses.
  150  */
  151         .align  ALIGN
  152         .globl  EXT(gdtptr)
  153 LEXT(gdtptr)
  154         .word   Times(8,GDTSZ)-1
  155         .long   EXT(gdt)+KVTOLINEAR
  156 
  157         .align  ALIGN
  158         .globl  EXT(idtptr)
  159 LEXT(idtptr)
  160         .word   Times(8,IDTSZ)-1
  161         .long   EXT(idt)+KVTOLINEAR
  162 
  163 #if     NCPUS > 1
  164         .data
  165         /*
  166          *      start_lock is very special.  We initialize the
  167          *      lock at allocation time rather than at run-time.
  168          *      Although start_lock should be an instance of a
  169          *      hw_lock, we hand-code all manipulation of the lock
  170          *      because the hw_lock code may require function calls;
  171          *      and we'd rather not introduce another dependency on
  172          *      a working stack at this point.
  173          */
  174         .globl  EXT(start_lock)
  175 EXT(start_lock):
  176         .long   0                       /* synchronizes processor startup */
  177 
  178         .globl  EXT(master_is_up)
  179 EXT(master_is_up):
  180         .long   0                       /* 1 when OK for other processors */
  181                                         /* to start */
  182         .globl  EXT(mp_boot_pde)
  183 EXT(mp_boot_pde):
  184         .long   0
  185 #endif  /* NCPUS > 1 */
  186 
  187 /*
  188  * All CPUs start here.
  189  *
  190  * Environment:
  191  *      protected mode, no paging, flat 32-bit address space.
  192  *      (Code/data/stack segments have base == 0, limit == 4G)
  193  */
  194         .text
  195         .align  ALIGN
  196         .globl  EXT(pstart)
  197         .globl  EXT(_start)
  198 LEXT(_start)
  199 LEXT(pstart)
  200         mov     %eax, %ebx              /* save pointer to kernbootstruct */
  201         mov     $0,%ax                  /* fs must be zeroed; */
  202         mov     %ax,%fs                 /* some bootstrappers don`t do this */
  203         mov     %ax,%gs
  204 
  205 #if     NCPUS > 1
  206         jmp     1f
  207 0:      cmpl    $0,PA(EXT(start_lock))
  208         jne     0b
  209 1:      movb    $1,%eax
  210         xchgl   %eax,PA(EXT(start_lock)) /* locked */
  211         testl   %eax,%eax
  212         jnz     0b
  213 
  214         cmpl    $0,PA(EXT(master_is_up))        /* are we first? */
  215         jne     EXT(slave_start)                /* no -- system already up. */
  216         movl    $1,PA(EXT(master_is_up))        /* others become slaves */
  217 #endif  /* NCPUS > 1 */
  218 
  219 /*
  220  * Get startup parameters.
  221  */
  222 
  223 #include <i386/AT386/asm_startup.h>
  224 
  225 /*
  226  * Build initial page table directory and page tables.
  227  * %ebx holds first available physical address.
  228  */
  229 
  230         addl    $(NBPG-1),%ebx          /* round first avail physical addr */
  231         andl    $(-NBPG),%ebx           /* to machine page size */
  232         leal    -KVTOPHYS(%ebx),%eax    /* convert to virtual address */
  233         movl    %eax,PA(EXT(kpde))      /* save as kernel page table directory */
  234         movl    %ebx,%cr3               /* set physical address in CR3 now */
  235 
  236         movl    %ebx,%edi               /* clear page table directory */
  237         movl    $(PTES_PER_PAGE),%ecx   /* one page of ptes */
  238         xorl    %eax,%eax
  239         cld
  240         rep
  241         stosl                           /* edi now points to next page */
  242 
  243 /*
  244  * Use next few pages for page tables.
  245  */
  246         addl    $(KERNELBASEPDE),%ebx   /* point to pde for kernel base */
  247         movl    %edi,%esi               /* point to end of current pte page */
  248 
  249 /*
  250  * Enter 1-1 mappings for kernel and for kernel page tables.
  251  */
  252         movl    $(INTEL_PTE_KERNEL),%eax /* set up pte prototype */
  253 0:
  254         cmpl    %esi,%edi               /* at end of pte page? */
  255         jb      1f                      /* if so: */
  256         movl    %edi,%edx               /*    get pte address (physical) */
  257         andl    $(-NBPG),%edx           /*    mask out offset in page */
  258         orl     $(INTEL_PTE_KERNEL),%edx /*   add pte bits */
  259         movl    %edx,(%ebx)             /*    set pde */
  260         addl    $4,%ebx                 /*    point to next pde */
  261         movl    %edi,%esi               /*    point to */
  262         addl    $(NBPG),%esi            /*    end of new pte page */
  263 1:
  264         movl    %eax,(%edi)             /* set pte */
  265         addl    $4,%edi                 /* advance to next pte */
  266         addl    $(NBPG),%eax            /* advance to next phys page */
  267         cmpl    %edi,%eax               /* have we mapped this pte page yet? */
  268         jb      0b                      /* loop if not */
  269 
  270 /*
  271  * Zero rest of last pte page.
  272  */
  273         xor     %eax,%eax               /* don`t map yet */
  274 2:      cmpl    %esi,%edi               /* at end of pte page? */
  275         jae     3f
  276         movl    %eax,(%edi)             /* zero mapping */
  277         addl    $4,%edi
  278         jmp     2b
  279 3:
  280 
  281 #if     NCPUS > 1
  282 /*
  283  * Grab (waste?) another page for a bootstrap page directory
  284  * for the other CPUs.  We don't want the running CPUs to see
  285  * addresses 0..3fffff mapped 1-1.
  286  */
  287         movl    %edi,PA(EXT(mp_boot_pde)) /* save its physical address */
  288         movl    $(PTES_PER_PAGE),%ecx   /* and clear it */
  289         rep
  290         stosl
  291 #endif  /* NCPUS > 1 */
  292         movl    %edi,PA(EXT(first_avail)) /* save first available phys addr */
  293 
  294 /*
  295  * pmap_bootstrap will enter rest of mappings.
  296  */
  297 
  298 /*
  299  * Fix initial descriptor tables.
  300  */
  301         lea     PA(EXT(idt)),%esi       /* fix IDT */
  302         movl    $(IDTSZ),%ecx
  303         movl    $(PA(fix_idt_ret)),%ebx
  304         jmp     fix_desc_common         /* (cannot use stack) */
  305 fix_idt_ret:
  306 
  307         lea     PA(EXT(gdt)),%esi       /* fix GDT */
  308         movl    $(GDTSZ),%ecx
  309         movl    $(PA(fix_gdt_ret)),%ebx
  310         jmp     fix_desc_common         /* (cannot use stack) */
  311 fix_gdt_ret:
  312 
  313         lea     PA(EXT(ldt)),%esi       /* fix LDT */
  314         movl    $(LDTSZ),%ecx
  315         movl    $(PA(fix_ldt_ret)),%ebx
  316         jmp     fix_desc_common         /* (cannot use stack) */
  317 fix_ldt_ret:
  318 
  319 /*
  320  * Turn on paging.
  321  */
  322         movl    %cr3,%eax               /* retrieve kernel PDE phys address */
  323         movl    KERNELBASEPDE(%eax),%ecx
  324         movl    %ecx,(%eax)             /* set it also as pte for location */
  325                                         /* 0..3fffff, so that the code */
  326                                         /* that enters paged mode is mapped */
  327                                         /* to identical addresses after */
  328                                         /* paged mode is enabled */
  329 
  330         addl    $4,%eax                 /* 400000..7fffff */
  331         movl    KERNELBASEPDE(%eax),%ecx
  332         movl    %ecx,(%eax)
  333 
  334         movl    $ EXT(pag_start),%ebx   /* first paged code address */
  335 
  336         movl    %cr0,%eax
  337         orl     $(CR0_PG),%eax          /* set PG bit in CR0 */
  338         orl     $(CR0_WP),%eax
  339         movl    %eax,%cr0               /* to enable paging */
  340 
  341         jmp     *%ebx                   /* flush prefetch queue */
  342 
  343 /*
  344  * We are now paging, and can run with correct addresses.
  345  */
  346 LEXT(pag_start)
  347         lgdt    EXT(gdtptr)             /* load GDT */
  348         lidt    EXT(idtptr)             /* load IDT */
  349         LJMP(KERNEL_CS,EXT(vstart))     /* switch to kernel code segment */
  350 
  351 /*
  352  * Master is now running with correct addresses.
  353  */
  354 LEXT(vstart)
  355         mov     $(KERNEL_DS),%ax        /* set kernel data segment */
  356         mov     %ax,%ds
  357         mov     %ax,%es
  358         mov     %ax,%ss
  359         mov     %ax,EXT(ktss)+TSS_SS0   /* set kernel stack segment */
  360                                         /* for traps to kernel */
  361 #if     MACH_KDB
  362         mov     %ax,EXT(dbtss)+TSS_SS0  /* likewise for debug task switch */
  363         mov     %cr3,%eax               /* get PDBR into debug TSS */
  364         mov     %eax,EXT(dbtss)+TSS_PDBR
  365         mov     $0,%eax
  366 #endif
  367 
  368         movw    $(KERNEL_LDT),%ax       /* get LDT segment */
  369         lldt    %ax                     /* load LDT */
  370 #if     MACH_KDB
  371         mov     %ax,EXT(ktss)+TSS_LDT   /* store LDT in two TSS, as well... */
  372         mov     %ax,EXT(dbtss)+TSS_LDT  /*   ...matters if we switch tasks */
  373 #endif
  374         movw    $(KERNEL_TSS),%ax
  375         ltr     %ax                     /* set up KTSS */
  376 
  377         mov     $ CPU_DATA,%ax
  378         mov     %ax,%gs
  379 
  380         lea     EXT(eintstack),%esp     /* switch to the bootup stack */
  381         call    EXT(i386_init)          /* run C code */
  382         /*NOTREACHED*/
  383         hlt
  384 
  385 #if     NCPUS > 1
  386 /*
  387  * master_up is used by the master cpu to signify that it is done
  388  * with the interrupt stack, etc. See the code in pstart and svstart
  389  * that this interlocks with.
  390  */
  391         .align  ALIGN
  392         .globl  EXT(master_up)
  393 LEXT(master_up)
  394         pushl   %ebp                    /* set up */
  395         movl    %esp,%ebp               /* stack frame */
  396         movl    $0,%ecx                 /* unlock start_lock */
  397         xchgl   %ecx,EXT(start_lock)    /* since we are no longer using */
  398                                         /* bootstrap stack */
  399         leave                           /* pop stack frame */
  400         ret
  401 
  402 /*
  403  * We aren't the first.  Call slave_main to initialize the processor
  404  * and get Mach going on it.
  405  */
  406         .align  ALIGN
  407         .globl  EXT(slave_start)
  408 LEXT(slave_start)
  409         cli                             /* disable interrupts, so we don`t */
  410                                         /* need IDT for a while */
  411         movl    EXT(kpde)+KVTOPHYS,%ebx /* get PDE virtual address */
  412         addl    $(KVTOPHYS),%ebx        /* convert to physical address */
  413 
  414         movl    PA(EXT(mp_boot_pde)),%edx /* point to the bootstrap PDE */
  415         movl    KERNELBASEPDE(%ebx),%eax
  416                                         /* point to pte for KERNELBASE */
  417         movl    %eax,KERNELBASEPDE(%edx)
  418                                         /* set in bootstrap PDE */
  419         movl    %eax,(%edx)             /* set it also as pte for location */
  420                                         /* 0..3fffff, so that the code */
  421                                         /* that enters paged mode is mapped */
  422                                         /* to identical addresses after */
  423                                         /* paged mode is enabled */
  424         movl    %edx,%cr3               /* use bootstrap PDE to enable paging */
  425 
  426         movl    $ EXT(spag_start),%edx  /* first paged code address */
  427 
  428         movl    %cr0,%eax
  429         orl     $(CR0_PG),%eax          /* set PG bit in CR0 */
  430         orl     $(CR0_WP),%eax
  431         movl    %eax,%cr0               /* to enable paging */
  432 
  433         jmp     *%edx                   /* flush prefetch queue. */
  434 
  435 /*
  436  * We are now paging, and can run with correct addresses.
  437  */
  438 LEXT(spag_start)
  439 
  440         lgdt    EXT(gdtptr)             /* load GDT */
  441         lidt    EXT(idtptr)             /* load IDT */
  442         LJMP(KERNEL_CS,EXT(svstart))    /* switch to kernel code segment */
  443 
  444 /*
  445  * Slave is now running with correct addresses.
  446  */
  447 LEXT(svstart)
  448         mov     $(KERNEL_DS),%ax        /* set kernel data segment */
  449         mov     %ax,%ds
  450         mov     %ax,%es
  451         mov     %ax,%ss
  452 
  453         movl    %ebx,%cr3               /* switch to the real kernel PDE  */
  454 
  455         CPU_NUMBER(%eax)
  456         movl    CX(EXT(interrupt_stack),%eax),%esp /* get stack */
  457         addl    $(INTSTACK_SIZE),%esp   /* point to top */
  458         xorl    %ebp,%ebp               /* for completeness */
  459 
  460         movl    $0,%ecx                 /* unlock start_lock */
  461         xchgl   %ecx,EXT(start_lock)    /* since we are no longer using */
  462                                         /* bootstrap stack */
  463 
  464 /*
  465  * switch to the per-cpu descriptor tables
  466  */
  467 
  468         pushl   %eax                    /* pass CPU number */
  469         call    EXT(mp_desc_init)       /* set up local table */
  470                                         /* pointer returned in %eax */
  471         subl    $4,%esp                 /* get space to build pseudo-descriptors */
  472         
  473         CPU_NUMBER(%eax)
  474         movw    $(GDTSZ*8-1),0(%esp)    /* set GDT size in GDT descriptor */
  475         movl    CX(EXT(mp_gdt),%eax),%edx
  476         addl    $ KVTOLINEAR,%edx
  477         movl    %edx,2(%esp)            /* point to local GDT (linear address) */
  478         lgdt    0(%esp)                 /* load new GDT */
  479         
  480         movw    $(IDTSZ*8-1),0(%esp)    /* set IDT size in IDT descriptor */
  481         movl    CX(EXT(mp_idt),%eax),%edx
  482         addl    $ KVTOLINEAR,%edx
  483         movl    %edx,2(%esp)            /* point to local IDT (linear address) */
  484         lidt    0(%esp)                 /* load new IDT */
  485         
  486         movw    $(KERNEL_LDT),%ax       /* get LDT segment */
  487         lldt    %ax                     /* load LDT */
  488 
  489         movw    $(KERNEL_TSS),%ax
  490         ltr     %ax                     /* load new KTSS */
  491 
  492         mov     $ CPU_DATA,%ax
  493         mov     %ax,%gs
  494 
  495         call    EXT(slave_main)         /* start MACH */
  496         /*NOTREACHED*/
  497         hlt
  498 #endif  /* NCPUS > 1 */
  499 
  500 /*
  501  * Convert a descriptor from fake to real format.
  502  *
  503  * Calls from assembly code:
  504  * %ebx = return address (physical) CANNOT USE STACK
  505  * %esi = descriptor table address (physical)
  506  * %ecx = number of descriptors
  507  *
  508  * Calls from C:
  509  * 0(%esp) = return address
  510  * 4(%esp) = descriptor table address (physical)
  511  * 8(%esp) = number of descriptors
  512  *
  513  * Fake descriptor format:
  514  *      bytes 0..3              base 31..0
  515  *      bytes 4..5              limit 15..0
  516  *      byte  6                 access byte 2 | limit 19..16
  517  *      byte  7                 access byte 1
  518  *
  519  * Real descriptor format:
  520  *      bytes 0..1              limit 15..0
  521  *      bytes 2..3              base 15..0
  522  *      byte  4                 base 23..16
  523  *      byte  5                 access byte 1
  524  *      byte  6                 access byte 2 | limit 19..16
  525  *      byte  7                 base 31..24
  526  *
  527  * Fake gate format:
  528  *      bytes 0..3              offset
  529  *      bytes 4..5              selector
  530  *      byte  6                 word count << 4 (to match fake descriptor)
  531  *      byte  7                 access byte 1
  532  *
  533  * Real gate format:
  534  *      bytes 0..1              offset 15..0
  535  *      bytes 2..3              selector
  536  *      byte  4                 word count
  537  *      byte  5                 access byte 1
  538  *      bytes 6..7              offset 31..16
  539  */
  540         .globl  EXT(fix_desc)
  541 LEXT(fix_desc)
  542         pushl   %ebp                    /* set up */
  543         movl    %esp,%ebp               /* stack frame */
  544         pushl   %esi                    /* save registers */
  545         pushl   %ebx
  546         movl    B_ARG0,%esi             /* point to first descriptor */
  547         movl    B_ARG1,%ecx             /* get number of descriptors */
  548         lea     0f,%ebx                 /* get return address */
  549         jmp     fix_desc_common         /* call internal routine */
  550 0:      popl    %ebx                    /* restore registers */
  551         popl    %esi
  552         leave                           /* pop stack frame */
  553         ret                             /* return */
  554 
  555 fix_desc_common:
  556 0:
  557         movw    6(%esi),%dx             /* get access byte */
  558         movb    %dh,%al
  559         andb    $0x14,%al
  560         cmpb    $0x04,%al               /* gate or descriptor? */
  561         je      1f
  562 
  563 /* descriptor */
  564         movl    0(%esi),%eax            /* get base in eax */
  565         rol     $16,%eax                /* swap 15..0 with 31..16 */
  566                                         /* (15..0 in correct place) */
  567         movb    %al,%dl                 /* combine bits 23..16 with ACC1 */
  568                                         /* in dh/dl */
  569         movb    %ah,7(%esi)             /* store bits 31..24 in correct place */
  570         movw    4(%esi),%ax             /* move limit bits 0..15 to word 0 */
  571         movl    %eax,0(%esi)            /* store (bytes 0..3 correct) */
  572         movw    %dx,4(%esi)             /* store bytes 4..5 */
  573         jmp     2f
  574 
  575 /* gate */
  576 1:
  577         movw    4(%esi),%ax             /* get selector */
  578         shrb    $4,%dl                  /* shift word count to proper place */
  579         movw    %dx,4(%esi)             /* store word count / ACC1 */
  580         movw    2(%esi),%dx             /* get offset 16..31 */
  581         movw    %dx,6(%esi)             /* store in correct place */
  582         movw    %ax,2(%esi)             /* store selector in correct place */
  583 2:
  584         addl    $8,%esi                 /* bump to next descriptor */
  585         loop    0b                      /* repeat */
  586         jmp     *%ebx                   /* all done */
  587 
  588 /*
  589  * put arg in kbd leds and spin a while
  590  * eats eax, ecx, edx
  591  */
  592 #define K_RDWR          0x60
  593 #define K_CMD_LEDS      0xed
  594 #define K_STATUS        0x64
  595 #define K_IBUF_FULL     0x02            /* input (to kbd) buffer full */
  596 #define K_OBUF_FULL     0x01            /* output (from kbd) buffer full */
  597 
  598 ENTRY(set_kbd_leds)
  599         mov     S_ARG0,%cl              /* save led value */
  600         
  601 0:      inb     $(K_STATUS),%al         /* get kbd status */
  602         testb   $(K_IBUF_FULL),%al      /* input busy? */
  603         jne     0b                      /* loop until not */
  604         
  605         mov     $(K_CMD_LEDS),%al       /* K_CMD_LEDS */
  606         outb    %al,$(K_RDWR)           /* to kbd */
  607 
  608 0:      inb     $(K_STATUS),%al         /* get kbd status */
  609         testb   $(K_OBUF_FULL),%al      /* output present? */
  610         je      0b                      /* loop if not */
  611 
  612         inb     $(K_RDWR),%al           /* read status (and discard) */
  613 
  614 0:      inb     $(K_STATUS),%al         /* get kbd status */
  615         testb   $(K_IBUF_FULL),%al      /* input busy? */
  616         jne     0b                      /* loop until not */
  617         
  618         mov     %cl,%al                 /* move led value */
  619         outb    %al,$(K_RDWR)           /* to kbd */
  620 
  621         movl    $10000000,%ecx          /* spin */
  622 0:      nop
  623         nop
  624         loop    0b                      /* a while */
  625 
  626         ret

Cache object: ad07627506ba73326193b77129ad4f9d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.