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/kernel/klib386.s

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 # 
    2 ! sections
    3 
    4 .sect .text; .sect .rom; .sect .data; .sect .bss
    5 
    6 #include <minix/config.h>
    7 #include <minix/const.h>
    8 #include "const.h"
    9 #include "sconst.h"
   10 #include "protect.h"
   11 
   12 ! This file contains a number of assembly code utility routines needed by the
   13 ! kernel.  They are:
   14 
   15 .define _monitor        ! exit Minix and return to the monitor
   16 .define _int86          ! let the monitor make an 8086 interrupt call
   17 .define _cp_mess        ! copies messages from source to destination
   18 .define _exit           ! dummy for library routines
   19 .define __exit          ! dummy for library routines
   20 .define ___exit         ! dummy for library routines
   21 .define ___main         ! dummy for GCC
   22 .define _phys_insw      ! transfer data from (disk controller) port to memory
   23 .define _phys_insb      ! likewise byte by byte
   24 .define _phys_outsw     ! transfer data from memory to (disk controller) port
   25 .define _phys_outsb     ! likewise byte by byte
   26 .define _enable_irq     ! enable an irq at the 8259 controller
   27 .define _disable_irq    ! disable an irq
   28 .define _phys_copy      ! copy data from anywhere to anywhere in memory
   29 .define _phys_memset    ! write pattern anywhere in memory
   30 .define _mem_rdw        ! copy one word from [segment:offset]
   31 .define _reset          ! reset the system
   32 .define _idle_task      ! task executed when there is no work
   33 .define _level0         ! call a function at level 0
   34 .define _read_tsc       ! read the cycle counter (Pentium and up)
   35 .define _read_cpu_flags ! read the cpu flags
   36 .define _read_cr0       ! read cr0
   37 .define _write_cr0      ! write a value in cr0
   38 .define _write_cr3      ! write a value in cr3 (root of the page table)
   39 
   40 ! The routines only guarantee to preserve the registers the C compiler
   41 ! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and
   42 ! direction bit in the flags).
   43 
   44 .sect .text
   45 !*===========================================================================*
   46 !*                              monitor                                      *
   47 !*===========================================================================*
   48 ! PUBLIC void monitor();
   49 ! Return to the monitor.
   50 
   51 _monitor:
   52         mov     esp, (_mon_sp)          ! restore monitor stack pointer
   53     o16 mov     dx, SS_SELECTOR         ! monitor data segment
   54         mov     ds, dx
   55         mov     es, dx
   56         mov     fs, dx
   57         mov     gs, dx
   58         mov     ss, dx
   59         pop     edi
   60         pop     esi
   61         pop     ebp
   62     o16 retf                            ! return to the monitor
   63 
   64 
   65 !*===========================================================================*
   66 !*                              int86                                        *
   67 !*===========================================================================*
   68 ! PUBLIC void int86();
   69 _int86:
   70         cmpb    (_mon_return), 0        ! is the monitor there?
   71         jnz     0f
   72         movb    ah, 0x01                ! an int 13 error seems appropriate
   73         movb    (_reg86+ 0), ah         ! reg86.w.f = 1 (set carry flag)
   74         movb    (_reg86+13), ah         ! reg86.b.ah = 0x01 = "invalid command"
   75         ret
   76 0:      push    ebp                     ! save C registers
   77         push    esi
   78         push    edi
   79         push    ebx
   80         pushf                           ! save flags
   81         cli                             ! no interruptions
   82 
   83         inb     INT2_CTLMASK
   84         movb    ah, al
   85         inb     INT_CTLMASK
   86         push    eax                     ! save interrupt masks
   87         mov     eax, (_irq_use)         ! map of in-use IRQ's
   88         and     eax, ~[1<<CLOCK_IRQ]    ! keep the clock ticking
   89         outb    INT_CTLMASK             ! enable all unused IRQ's and vv.
   90         movb    al, ah
   91         outb    INT2_CTLMASK
   92 
   93         mov     eax, SS_SELECTOR        ! monitor data segment
   94         mov     ss, ax
   95         xchg    esp, (_mon_sp)          ! switch stacks
   96         push    (_reg86+36)             ! parameters used in INT call
   97         push    (_reg86+32)
   98         push    (_reg86+28)
   99         push    (_reg86+24)
  100         push    (_reg86+20)
  101         push    (_reg86+16)
  102         push    (_reg86+12)
  103         push    (_reg86+ 8)
  104         push    (_reg86+ 4)
  105         push    (_reg86+ 0)
  106         mov     ds, ax                  ! remaining data selectors
  107         mov     es, ax
  108         mov     fs, ax
  109         mov     gs, ax
  110         push    cs
  111         push    return                  ! kernel return address and selector
  112     o16 jmpf    20+2*4+10*4+2*4(esp)    ! make the call
  113 return:
  114         pop     (_reg86+ 0)
  115         pop     (_reg86+ 4)
  116         pop     (_reg86+ 8)
  117         pop     (_reg86+12)
  118         pop     (_reg86+16)
  119         pop     (_reg86+20)
  120         pop     (_reg86+24)
  121         pop     (_reg86+28)
  122         pop     (_reg86+32)
  123         pop     (_reg86+36)
  124         lgdt    (_gdt+GDT_SELECTOR)     ! reload global descriptor table
  125         jmpf    CS_SELECTOR:csinit      ! restore everything
  126 csinit: mov     eax, DS_SELECTOR
  127         mov     ds, ax
  128         mov     es, ax
  129         mov     fs, ax
  130         mov     gs, ax
  131         mov     ss, ax
  132         xchg    esp, (_mon_sp)          ! unswitch stacks
  133         lidt    (_gdt+IDT_SELECTOR)     ! reload interrupt descriptor table
  134         andb    (_gdt+TSS_SELECTOR+DESC_ACCESS), ~0x02  ! clear TSS busy bit
  135         mov     eax, TSS_SELECTOR
  136         ltr     ax                      ! set TSS register
  137 
  138         pop     eax
  139         outb    INT_CTLMASK             ! restore interrupt masks
  140         movb    al, ah
  141         outb    INT2_CTLMASK
  142 
  143         add     (_lost_ticks), ecx      ! record lost clock ticks
  144 
  145         popf                            ! restore flags
  146         pop     ebx                     ! restore C registers
  147         pop     edi
  148         pop     esi
  149         pop     ebp
  150         ret
  151 
  152 
  153 !*===========================================================================*
  154 !*                              cp_mess                                      *
  155 !*===========================================================================*
  156 ! PUBLIC void cp_mess(int src, phys_clicks src_clicks, vir_bytes src_offset,
  157 !                     phys_clicks dst_clicks, vir_bytes dst_offset);
  158 ! This routine makes a fast copy of a message from anywhere in the address
  159 ! space to anywhere else.  It also copies the source address provided as a
  160 ! parameter to the call into the first word of the destination message.
  161 !
  162 ! Note that the message size, "Msize" is in DWORDS (not bytes) and must be set
  163 ! correctly.  Changing the definition of message in the type file and not
  164 ! changing it here will lead to total disaster.
  165 
  166 CM_ARGS =       4 + 4 + 4 + 4 + 4       ! 4 + 4 + 4 + 4 + 4
  167 !               es  ds edi esi eip      proc scl sof dcl dof
  168 
  169         .align  16
  170 _cp_mess:
  171         cld
  172         push    esi
  173         push    edi
  174         push    ds
  175         push    es
  176 
  177         mov     eax, FLAT_DS_SELECTOR
  178         mov     ds, ax
  179         mov     es, ax
  180 
  181         mov     esi, CM_ARGS+4(esp)             ! src clicks
  182         shl     esi, CLICK_SHIFT
  183         add     esi, CM_ARGS+4+4(esp)           ! src offset
  184         mov     edi, CM_ARGS+4+4+4(esp)         ! dst clicks
  185         shl     edi, CLICK_SHIFT
  186         add     edi, CM_ARGS+4+4+4+4(esp)       ! dst offset
  187 
  188         mov     eax, CM_ARGS(esp)       ! process number of sender
  189         stos                            ! copy number of sender to dest message
  190         add     esi, 4                  ! do not copy first word
  191         mov     ecx, Msize - 1          ! remember, first word does not count
  192         rep
  193         movs                            ! copy the message
  194 
  195         pop     es
  196         pop     ds
  197         pop     edi
  198         pop     esi
  199         ret                             ! that is all folks!
  200 
  201 
  202 !*===========================================================================*
  203 !*                              exit                                         *
  204 !*===========================================================================*
  205 ! PUBLIC void exit();
  206 ! Some library routines use exit, so provide a dummy version.
  207 ! Actual calls to exit cannot occur in the kernel.
  208 ! GNU CC likes to call ___main from main() for nonobvious reasons.
  209 
  210 _exit:
  211 __exit:
  212 ___exit:
  213         sti
  214         jmp     ___exit
  215 
  216 ___main:
  217         ret
  218 
  219 
  220 !*===========================================================================*
  221 !*                              phys_insw                                    *
  222 !*===========================================================================*
  223 ! PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count);
  224 ! Input an array from an I/O port.  Absolute address version of insw().
  225 
  226 _phys_insw:
  227         push    ebp
  228         mov     ebp, esp
  229         cld
  230         push    edi
  231         push    es
  232         mov     ecx, FLAT_DS_SELECTOR
  233         mov     es, cx
  234         mov     edx, 8(ebp)             ! port to read from
  235         mov     edi, 12(ebp)            ! destination addr
  236         mov     ecx, 16(ebp)            ! byte count
  237         shr     ecx, 1                  ! word count
  238 rep o16 ins                             ! input many words
  239         pop     es
  240         pop     edi
  241         pop     ebp
  242         ret
  243 
  244 
  245 !*===========================================================================*
  246 !*                              phys_insb                                    *
  247 !*===========================================================================*
  248 ! PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count);
  249 ! Input an array from an I/O port.  Absolute address version of insb().
  250 
  251 _phys_insb:
  252         push    ebp
  253         mov     ebp, esp
  254         cld
  255         push    edi
  256         push    es
  257         mov     ecx, FLAT_DS_SELECTOR
  258         mov     es, cx
  259         mov     edx, 8(ebp)             ! port to read from
  260         mov     edi, 12(ebp)            ! destination addr
  261         mov     ecx, 16(ebp)            ! byte count
  262 !       shr     ecx, 1                  ! word count
  263    rep  insb                            ! input many bytes
  264         pop     es
  265         pop     edi
  266         pop     ebp
  267         ret
  268 
  269 
  270 !*===========================================================================*
  271 !*                              phys_outsw                                   *
  272 !*===========================================================================*
  273 ! PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count);
  274 ! Output an array to an I/O port.  Absolute address version of outsw().
  275 
  276         .align  16
  277 _phys_outsw:
  278         push    ebp
  279         mov     ebp, esp
  280         cld
  281         push    esi
  282         push    ds
  283         mov     ecx, FLAT_DS_SELECTOR
  284         mov     ds, cx
  285         mov     edx, 8(ebp)             ! port to write to
  286         mov     esi, 12(ebp)            ! source addr
  287         mov     ecx, 16(ebp)            ! byte count
  288         shr     ecx, 1                  ! word count
  289 rep o16 outs                            ! output many words
  290         pop     ds
  291         pop     esi
  292         pop     ebp
  293         ret
  294 
  295 
  296 !*===========================================================================*
  297 !*                              phys_outsb                                   *
  298 !*===========================================================================*
  299 ! PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count);
  300 ! Output an array to an I/O port.  Absolute address version of outsb().
  301 
  302         .align  16
  303 _phys_outsb:
  304         push    ebp
  305         mov     ebp, esp
  306         cld
  307         push    esi
  308         push    ds
  309         mov     ecx, FLAT_DS_SELECTOR
  310         mov     ds, cx
  311         mov     edx, 8(ebp)             ! port to write to
  312         mov     esi, 12(ebp)            ! source addr
  313         mov     ecx, 16(ebp)            ! byte count
  314    rep  outsb                           ! output many bytes
  315         pop     ds
  316         pop     esi
  317         pop     ebp
  318         ret
  319 
  320 
  321 !*==========================================================================*
  322 !*                              enable_irq                                  *
  323 !*==========================================================================*/
  324 ! PUBLIC void enable_irq(irq_hook_t *hook)
  325 ! Enable an interrupt request line by clearing an 8259 bit.
  326 ! Equivalent C code for hook->irq < 8:
  327 !   if ((irq_actids[hook->irq] &= ~hook->id) == 0)
  328 !       outb(INT_CTLMASK, inb(INT_CTLMASK) & ~(1 << irq));
  329 
  330         .align  16
  331 _enable_irq:
  332         push    ebp
  333         mov     ebp, esp
  334         pushf
  335         cli
  336         mov     eax, 8(ebp)             ! hook
  337         mov     ecx, 8(eax)             ! irq
  338         mov     eax, 12(eax)            ! id bit
  339         not     eax
  340         and     _irq_actids(ecx*4), eax ! clear this id bit
  341         jnz     en_done                 ! still masked by other handlers?
  342         movb    ah, ~1
  343         rolb    ah, cl                  ! ah = ~(1 << (irq % 8))
  344         mov     edx, INT_CTLMASK        ! enable irq < 8 at the master 8259
  345         cmpb    cl, 8
  346         jb      0f
  347         mov     edx, INT2_CTLMASK       ! enable irq >= 8 at the slave 8259
  348 0:      inb     dx
  349         andb    al, ah
  350         outb    dx                      ! clear bit at the 8259
  351 en_done:popf
  352         leave
  353         ret
  354 
  355 
  356 !*==========================================================================*
  357 !*                              disable_irq                                 *
  358 !*==========================================================================*/
  359 ! PUBLIC int disable_irq(irq_hook_t *hook)
  360 ! Disable an interrupt request line by setting an 8259 bit.
  361 ! Equivalent C code for irq < 8:
  362 !   irq_actids[hook->irq] |= hook->id;
  363 !   outb(INT_CTLMASK, inb(INT_CTLMASK) | (1 << irq));
  364 ! Returns true iff the interrupt was not already disabled.
  365 
  366         .align  16
  367 _disable_irq:
  368         push    ebp
  369         mov     ebp, esp
  370         pushf
  371         cli
  372         mov     eax, 8(ebp)             ! hook
  373         mov     ecx, 8(eax)             ! irq
  374         mov     eax, 12(eax)            ! id bit
  375         or      _irq_actids(ecx*4), eax ! set this id bit
  376         movb    ah, 1
  377         rolb    ah, cl                  ! ah = (1 << (irq % 8))
  378         mov     edx, INT_CTLMASK        ! disable irq < 8 at the master 8259
  379         cmpb    cl, 8
  380         jb      0f
  381         mov     edx, INT2_CTLMASK       ! disable irq >= 8 at the slave 8259
  382 0:      inb     dx
  383         testb   al, ah
  384         jnz     dis_already             ! already disabled?
  385         orb     al, ah
  386         outb    dx                      ! set bit at the 8259
  387         mov     eax, 1                  ! disabled by this function
  388         popf
  389         leave
  390         ret
  391 dis_already:
  392         xor     eax, eax                ! already disabled
  393         popf
  394         leave
  395         ret
  396 
  397 
  398 !*===========================================================================*
  399 !*                              phys_copy                                    *
  400 !*===========================================================================*
  401 ! PUBLIC void phys_copy(phys_bytes source, phys_bytes destination,
  402 !                       phys_bytes bytecount);
  403 ! Copy a block of physical memory.
  404 
  405 PC_ARGS =       4 + 4 + 4 + 4   ! 4 + 4 + 4
  406 !               es edi esi eip   src dst len
  407 
  408         .align  16
  409 _phys_copy:
  410         cld
  411         push    esi
  412         push    edi
  413         push    es
  414 
  415         mov     eax, FLAT_DS_SELECTOR
  416         mov     es, ax
  417 
  418         mov     esi, PC_ARGS(esp)
  419         mov     edi, PC_ARGS+4(esp)
  420         mov     eax, PC_ARGS+4+4(esp)
  421 
  422         cmp     eax, 10                 ! avoid align overhead for small counts
  423         jb      pc_small
  424         mov     ecx, esi                ! align source, hope target is too
  425         neg     ecx
  426         and     ecx, 3                  ! count for alignment
  427         sub     eax, ecx
  428         rep
  429    eseg movsb
  430         mov     ecx, eax
  431         shr     ecx, 2                  ! count of dwords
  432         rep
  433    eseg movs
  434         and     eax, 3
  435 pc_small:
  436         xchg    ecx, eax                ! remainder
  437         rep
  438    eseg movsb
  439 
  440         pop     es
  441         pop     edi
  442         pop     esi
  443         ret
  444 
  445 !*===========================================================================*
  446 !*                              phys_memset                                  *
  447 !*===========================================================================*
  448 ! PUBLIC void phys_memset(phys_bytes source, unsigned long pattern,
  449 !       phys_bytes bytecount);
  450 ! Fill a block of physical memory with pattern.
  451 
  452         .align  16
  453 _phys_memset:
  454         push    ebp
  455         mov     ebp, esp
  456         push    esi
  457         push    ebx
  458         push    ds
  459         mov     esi, 8(ebp)
  460         mov     eax, 16(ebp)
  461         mov     ebx, FLAT_DS_SELECTOR
  462         mov     ds, bx
  463         mov     ebx, 12(ebp)
  464         shr     eax, 2
  465 fill_start:
  466         mov     (esi), ebx
  467         add     esi, 4
  468         dec     eax
  469         jnz     fill_start
  470         ! Any remaining bytes?
  471         mov     eax, 16(ebp)
  472         and     eax, 3
  473 remain_fill:
  474         cmp     eax, 0
  475         jz      fill_done
  476         movb    bl, 12(ebp)
  477         movb    (esi), bl
  478         add     esi, 1
  479         inc     ebp
  480         dec     eax
  481         jmp     remain_fill
  482 fill_done:
  483         pop     ds
  484         pop     ebx
  485         pop     esi
  486         pop     ebp
  487         ret
  488 
  489 !*===========================================================================*
  490 !*                              mem_rdw                                      *
  491 !*===========================================================================*
  492 ! PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset);
  493 ! Load and return word at far pointer segment:offset.
  494 
  495         .align  16
  496 _mem_rdw:
  497         mov     cx, ds
  498         mov     ds, 4(esp)              ! segment
  499         mov     eax, 4+4(esp)           ! offset
  500         movzx   eax, (eax)              ! word to return
  501         mov     ds, cx
  502         ret
  503 
  504 
  505 !*===========================================================================*
  506 !*                              reset                                        *
  507 !*===========================================================================*
  508 ! PUBLIC void reset();
  509 ! Reset the system by loading IDT with offset 0 and interrupting.
  510 
  511 _reset:
  512         lidt    (idt_zero)
  513         int     3               ! anything goes, the 386 will not like it
  514 .sect .data
  515 idt_zero:       .data4  0, 0
  516 .sect .text
  517 
  518 
  519 !*===========================================================================*
  520 !*                              idle_task                                    *
  521 !*===========================================================================*
  522 _idle_task:
  523 ! This task is called when the system has nothing else to do.  The HLT
  524 ! instruction puts the processor in a state where it draws minimum power.
  525         push    halt
  526         call    _level0         ! level0(halt)
  527         pop     eax
  528         jmp     _idle_task
  529 halt:
  530         sti
  531         hlt
  532         cli
  533         ret
  534 
  535 !*===========================================================================*
  536 !*                            level0                                         *
  537 !*===========================================================================*
  538 ! PUBLIC void level0(void (*func)(void))
  539 ! Call a function at permission level 0.  This allows kernel tasks to do
  540 ! things that are only possible at the most privileged CPU level.
  541 !
  542 _level0:
  543         mov     eax, 4(esp)
  544         mov     (_level0_func), eax
  545         int     LEVEL0_VECTOR
  546         ret
  547 
  548 
  549 !*===========================================================================*
  550 !*                            read_tsc                                       *
  551 !*===========================================================================*
  552 ! PUBLIC void read_tsc(unsigned long *high, unsigned long *low);
  553 ! Read the cycle counter of the CPU. Pentium and up. 
  554 .align 16
  555 _read_tsc:
  556 .data1 0x0f             ! this is the RDTSC instruction 
  557 .data1 0x31             ! it places the TSC in EDX:EAX
  558         push ebp
  559         mov ebp, 8(esp)
  560         mov (ebp), edx
  561         mov ebp, 12(esp)
  562         mov (ebp), eax
  563         pop ebp
  564         ret
  565 
  566 !*===========================================================================*
  567 !*                            read_flags                                             *
  568 !*===========================================================================*
  569 ! PUBLIC unsigned long read_cpu_flags(void);
  570 ! Read CPU status flags from C.
  571 .align 16
  572 _read_cpu_flags:
  573         pushf
  574         mov eax, (esp)
  575         popf
  576         ret
  577 
  578 
  579 !*===========================================================================*
  580 !*                            read_cr0                                       *
  581 !*===========================================================================*
  582 ! PUBLIC unsigned long read_cr0(void);
  583 _read_cr0:
  584         push    ebp
  585         mov     ebp, esp
  586         mov     eax, cr0
  587         pop     ebp
  588         ret
  589 
  590 !*===========================================================================*
  591 !*                            write_cr0                                      *
  592 !*===========================================================================*
  593 ! PUBLIC void write_cr0(unsigned long value);
  594 _write_cr0:
  595         push    ebp
  596         mov     ebp, esp
  597         mov     eax, 8(ebp)
  598         mov     cr0, eax
  599         jmp     0f              ! A jump is required for some flags
  600 0:
  601         pop     ebp
  602         ret
  603 
  604 !*===========================================================================*
  605 !*                            write_cr3                                      *
  606 !*===========================================================================*
  607 ! PUBLIC void write_cr3(unsigned long value);
  608 _write_cr3:
  609         push    ebp
  610         mov     ebp, esp
  611         mov     eax, 8(ebp)
  612         mov     cr3, eax
  613         pop     ebp
  614         ret
  615 

Cache object: 5a814cf3b0b83772d92d91dc8b3b869b


[ 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.