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/i386/isa/random_machdep.c

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  * random_machdep.c -- A strong random number generator
    3  *
    4  * $FreeBSD: src/sys/i386/isa/random_machdep.c,v 1.13.2.2 1999/09/05 08:13:22 peter Exp $
    5  *
    6  * Version 0.95, last modified 18-Oct-95
    7  * 
    8  * Copyright Theodore Ts'o, 1994, 1995.  All rights reserved.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, and the entire permission notice in its entirety,
   15  *    including the disclaimer of warranties.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. The name of the author may not be used to endorse or promote
   20  *    products derived from this software without specific prior
   21  *    written permission.
   22  * 
   23  * ALTERNATIVELY, this product may be distributed under the terms of
   24  * the GNU Public License, in which case the provisions of the GPL are
   25  * required INSTEAD OF the above restrictions.  (This clause is
   26  * necessary due to a potential bad interaction between the GPL and
   27  * the restrictions contained in a BSD-style copyright.)
   28  * 
   29  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
   30  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   31  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   32  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   39  * OF THE POSSIBILITY OF SUCH DAMAGE.
   40  */
   41 
   42 #include "opt_cpu.h"
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/kernel.h>
   47 #include <sys/select.h>
   48 #include <sys/fcntl.h>
   49 
   50 #include <machine/clock.h>
   51 #include <machine/random.h>
   52 
   53 #include <i386/isa/icu.h>
   54 #ifdef PC98
   55 #include <pc98/pc98/pc98.h>
   56 #else
   57 #include <i386/isa/isa.h>
   58 #endif
   59 #include <i386/isa/timerreg.h>
   60 
   61 #define MAX_BLKDEV 4
   62 
   63 /*
   64  * The pool is stirred with a primitive polynomial of degree 128
   65  * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
   66  * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
   67  */
   68 #define POOLWORDS 128    /* Power of 2 - note that this is 32-bit words */
   69 #define POOLBITS (POOLWORDS*32)
   70 
   71 #if POOLWORDS == 128
   72 #define TAP1    99     /* The polynomial taps */
   73 #define TAP2    59
   74 #define TAP3    31
   75 #define TAP4    9
   76 #define TAP5    7
   77 #elif POOLWORDS == 64
   78 #define TAP1    62      /* The polynomial taps */
   79 #define TAP2    38
   80 #define TAP3    10
   81 #define TAP4    6
   82 #define TAP5    1
   83 #else
   84 #error No primitive polynomial available for chosen POOLWORDS
   85 #endif
   86 
   87 #define WRITEBUFFER 512 /* size in bytes */
   88 
   89 /* There is actually only one of these, globally. */
   90 struct random_bucket {
   91         u_int   add_ptr;
   92         u_int   entropy_count;
   93         int     input_rotate;
   94         u_int32_t *pool;
   95         struct  selinfo rsel;
   96 };
   97 
   98 /* There is one of these per entropy source */
   99 struct timer_rand_state {
  100         u_long  last_time;
  101         int     last_delta;
  102         int     nbits;
  103 };
  104 
  105 static struct random_bucket random_state;
  106 static u_int32_t random_pool[POOLWORDS];
  107 static struct timer_rand_state keyboard_timer_state;
  108 static struct timer_rand_state extract_timer_state;
  109 static struct timer_rand_state irq_timer_state[ICU_LEN];
  110 #ifdef notyet
  111 static struct timer_rand_state blkdev_timer_state[MAX_BLKDEV];
  112 #endif
  113 static struct wait_queue *random_wait;
  114 
  115 inthand2_t *sec_intr_handler[ICU_LEN];
  116 int sec_intr_unit[ICU_LEN];
  117 
  118 #ifndef MIN
  119 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  120 #endif
  121         
  122 void
  123 rand_initialize(void)
  124 {
  125         random_state.add_ptr = 0;
  126         random_state.entropy_count = 0;
  127         random_state.pool = random_pool;
  128         random_wait = NULL;
  129         random_state.rsel.si_flags = 0;
  130         random_state.rsel.si_pid = 0;
  131 }
  132 
  133 /*
  134  * This function adds an int into the entropy "pool".  It does not
  135  * update the entropy estimate.  The caller must do this if appropriate.
  136  *
  137  * The pool is stirred with a primitive polynomial of degree 128
  138  * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
  139  * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
  140  * 
  141  * We rotate the input word by a changing number of bits, to help
  142  * assure that all bits in the entropy get toggled.  Otherwise, if we
  143  * consistently feed the entropy pool small numbers (like ticks and
  144  * scancodes, for example), the upper bits of the entropy pool don't
  145  * get affected. --- TYT, 10/11/95
  146  */
  147 static __inline void
  148 add_entropy_word(struct random_bucket *r, const u_int32_t input)
  149 {
  150         u_int i;
  151         u_int32_t w;
  152 
  153         w = (input << r->input_rotate) | (input >> (32 - r->input_rotate));
  154         i = r->add_ptr = (r->add_ptr - 1) & (POOLWORDS-1);
  155         if (i)
  156                 r->input_rotate = (r->input_rotate + 7) & 31;
  157         else
  158                 /*
  159                  * At the beginning of the pool, add an extra 7 bits
  160                  * rotation, so that successive passes spread the
  161                  * input bits across the pool evenly.
  162                  */
  163                 r->input_rotate = (r->input_rotate + 14) & 31;
  164 
  165         /* XOR in the various taps */
  166         w ^= r->pool[(i+TAP1)&(POOLWORDS-1)];
  167         w ^= r->pool[(i+TAP2)&(POOLWORDS-1)];
  168         w ^= r->pool[(i+TAP3)&(POOLWORDS-1)];
  169         w ^= r->pool[(i+TAP4)&(POOLWORDS-1)];
  170         w ^= r->pool[(i+TAP5)&(POOLWORDS-1)];
  171         w ^= r->pool[i];
  172         /* Rotate w left 1 bit (stolen from SHA) and store */
  173         r->pool[i] = (w << 1) | (w >> 31);
  174 }
  175 
  176 /*
  177  * This function adds entropy to the entropy "pool" by using timing
  178  * delays.  It uses the timer_rand_state structure to make an estimate
  179  * of how  any bits of entropy this call has added to the pool.
  180  *
  181  * The number "num" is also added to the pool - it should somehow describe
  182  * the type of event which just happened.  This is currently 0-255 for
  183  * keyboard scan codes, and 256 upwards for interrupts.
  184  * On the i386, this is assumed to be at most 16 bits, and the high bits
  185  * are used for a high-resolution timer.
  186  */
  187 static void
  188 add_timer_randomness(struct random_bucket *r, struct timer_rand_state *state,
  189         u_int num)
  190 {
  191         int             delta, delta2;
  192         u_int           nbits;
  193         u_int32_t       time;
  194 
  195 #if defined(I586_CPU) || defined(I686_CPU)
  196         if (i586_ctr_freq != 0) {
  197                 num ^= (u_int32_t) rdtsc() << 16;
  198                 r->entropy_count += 2;
  199         } else {
  200 #endif
  201                 disable_intr();
  202                 outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
  203                 num ^= inb(TIMER_CNTR0) << 16;
  204                 num ^= inb(TIMER_CNTR0) << 24;
  205                 enable_intr();
  206                 r->entropy_count += 2;
  207 #if defined(I586_CPU) || defined(I686_CPU)
  208         }
  209 #endif
  210                 
  211         time = ticks;
  212 
  213         add_entropy_word(r, (u_int32_t) num);
  214         add_entropy_word(r, time);
  215 
  216         /*
  217          * Calculate number of bits of randomness we probably
  218          * added.  We take into account the first and second order
  219          * deltas in order to make our estimate.
  220          */
  221         delta = time - state->last_time;
  222         state->last_time = time;
  223 
  224         delta2 = delta - state->last_delta;
  225         state->last_delta = delta;
  226 
  227         if (delta < 0) delta = -delta;
  228         if (delta2 < 0) delta2 = -delta2;
  229         delta = MIN(delta, delta2) >> 1;
  230         for (nbits = 0; delta; nbits++)
  231                 delta >>= 1;
  232 
  233         r->entropy_count += nbits;
  234         
  235         /* Prevent overflow */
  236         if (r->entropy_count > POOLBITS)
  237                 r->entropy_count = POOLBITS;
  238 
  239         if (r->entropy_count >= 8)
  240                 selwakeup(&random_state.rsel);
  241 }
  242 
  243 void
  244 add_keyboard_randomness(u_char scancode)
  245 {
  246         add_timer_randomness(&random_state, &keyboard_timer_state, scancode);
  247 }
  248 
  249 void
  250 add_interrupt_randomness(int irq)
  251 {
  252         (sec_intr_handler[irq])(sec_intr_unit[irq]);
  253         add_timer_randomness(&random_state, &irq_timer_state[irq], irq);
  254 }
  255 
  256 #ifdef notused
  257 void
  258 add_blkdev_randomness(int major)
  259 {
  260         if (major >= MAX_BLKDEV)
  261                 return;
  262 
  263         add_timer_randomness(&random_state, &blkdev_timer_state[major],
  264                              0x200+major);
  265 }
  266 #endif /* notused */
  267 
  268 /*
  269  * MD5 transform algorithm, taken from code written by Colin Plumb,
  270  * and put into the public domain
  271  *
  272  * QUESTION: Replace this with SHA, which as generally received better
  273  * reviews from the cryptographic community?
  274  */
  275 
  276 /* The four core functions - F1 is optimized somewhat */
  277 
  278 /* #define F1(x, y, z) (x & y | ~x & z) */
  279 #define F1(x, y, z) (z ^ (x & (y ^ z)))
  280 #define F2(x, y, z) F1(z, x, y)
  281 #define F3(x, y, z) (x ^ y ^ z)
  282 #define F4(x, y, z) (y ^ (x | ~z))
  283 
  284 /* This is the central step in the MD5 algorithm. */
  285 #define MD5STEP(f, w, x, y, z, data, s) \
  286         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
  287 
  288 /*
  289  * The core of the MD5 algorithm, this alters an existing MD5 hash to
  290  * reflect the addition of 16 longwords of new data.  MD5Update blocks
  291  * the data and converts bytes into longwords for this routine.
  292  */
  293 static void
  294 MD5Transform(u_int32_t buf[4],
  295                          u_int32_t const in[16])
  296 {
  297         u_int32_t a, b, c, d;
  298 
  299         a = buf[0];
  300         b = buf[1];
  301         c = buf[2];
  302         d = buf[3];
  303 
  304         MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
  305         MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
  306         MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
  307         MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
  308         MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
  309         MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
  310         MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
  311         MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
  312         MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
  313         MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
  314         MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
  315         MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
  316         MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
  317         MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
  318         MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
  319         MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
  320 
  321         MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
  322         MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
  323         MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
  324         MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
  325         MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
  326         MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
  327         MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
  328         MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
  329         MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
  330         MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
  331         MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
  332         MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
  333         MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
  334         MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
  335         MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
  336         MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
  337 
  338         MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
  339         MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
  340         MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
  341         MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
  342         MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
  343         MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
  344         MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
  345         MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
  346         MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
  347         MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
  348         MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
  349         MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
  350         MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
  351         MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
  352         MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
  353         MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
  354 
  355         MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
  356         MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
  357         MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
  358         MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
  359         MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
  360         MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
  361         MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
  362         MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
  363         MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
  364         MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
  365         MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
  366         MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
  367         MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
  368         MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
  369         MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
  370         MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
  371 
  372         buf[0] += a;
  373         buf[1] += b;
  374         buf[2] += c;
  375         buf[3] += d;
  376 }
  377 
  378 #undef F1
  379 #undef F2
  380 #undef F3
  381 #undef F4
  382 #undef MD5STEP
  383 
  384 
  385 #if POOLWORDS % 16
  386 #error extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
  387 #endif
  388 /*
  389  * This function extracts randomness from the "entropy pool", and
  390  * returns it in a buffer.  This function computes how many remaining
  391  * bits of entropy are left in the pool, but it does not restrict the
  392  * number of bytes that are actually obtained.
  393  */
  394 static __inline int
  395 extract_entropy(struct random_bucket *r, char *buf, int nbytes)
  396 {
  397         int ret, i;
  398         u_int32_t tmp[4];
  399         
  400         add_timer_randomness(r, &extract_timer_state, nbytes);
  401         
  402         /* Redundant, but just in case... */
  403         if (r->entropy_count > POOLBITS) 
  404                 r->entropy_count = POOLBITS;
  405         /* Why is this here?  Left in from Ted Ts'o.  Perhaps to limit time. */
  406         if (nbytes > 32768)
  407                 nbytes = 32768;
  408 
  409         ret = nbytes;
  410         if (r->entropy_count / 8 >= nbytes)
  411                 r->entropy_count -= nbytes*8;
  412         else
  413                 r->entropy_count = 0;
  414 
  415         while (nbytes) {
  416                 /* Hash the pool to get the output */
  417                 tmp[0] = 0x67452301;
  418                 tmp[1] = 0xefcdab89;
  419                 tmp[2] = 0x98badcfe;
  420                 tmp[3] = 0x10325476;
  421                 for (i = 0; i < POOLWORDS; i += 16)
  422                         MD5Transform(tmp, r->pool+i);
  423                 /* Modify pool so next hash will produce different results */
  424                 add_entropy_word(r, tmp[0]);
  425                 add_entropy_word(r, tmp[1]);
  426                 add_entropy_word(r, tmp[2]);
  427                 add_entropy_word(r, tmp[3]);
  428                 /*
  429                  * Run the MD5 Transform one more time, since we want
  430                  * to add at least minimal obscuring of the inputs to
  431                  * add_entropy_word().  --- TYT
  432                  */
  433                 MD5Transform(tmp, r->pool);
  434                 
  435                 /* Copy data to destination buffer */
  436                 i = MIN(nbytes, 16);
  437                 bcopy(tmp, buf, i);
  438                 nbytes -= i;
  439                 buf += i;
  440         }
  441 
  442         /* Wipe data from memory */
  443         bzero(tmp, sizeof(tmp));
  444         
  445         return ret;
  446 }
  447 
  448 #ifdef notused /* XXX NOT the exported kernel interface */
  449 /*
  450  * This function is the exported kernel interface.  It returns some
  451  * number of good random numbers, suitable for seeding TCP sequence
  452  * numbers, etc.
  453  */
  454 void
  455 get_random_bytes(void *buf, u_int nbytes)
  456 {
  457         extract_entropy(&random_state, (char *) buf, nbytes);
  458 }
  459 #endif /* notused */
  460 
  461 u_int
  462 read_random(char *buf, u_int nbytes)
  463 {
  464         if ((nbytes * 8) > random_state.entropy_count)
  465                 nbytes = random_state.entropy_count / 8;
  466         
  467         return extract_entropy(&random_state, buf, nbytes);
  468 }
  469 
  470 u_int
  471 read_random_unlimited(char *buf, u_int nbytes)
  472 {
  473         return extract_entropy(&random_state, buf, nbytes);
  474 }
  475 
  476 #ifdef notused
  477 u_int
  478 write_random(const char *buf, u_int nbytes)
  479 {
  480         u_int i;
  481         u_int32_t word, *p;
  482 
  483         for (i = nbytes, p = (u_int32_t *)buf;
  484              i >= sizeof(u_int32_t);
  485              i-= sizeof(u_int32_t), p++)
  486                 add_entropy_word(&random_state, *p);
  487         if (i) {
  488                 word = 0;
  489                 bcopy(p, &word, i);
  490                 add_entropy_word(&random_state, word);
  491         }
  492         return nbytes;
  493 }
  494 #endif /* notused */
  495 
  496 int
  497 random_select(dev_t dev, int rw, struct proc *p)
  498 {
  499         int s, ret;
  500 
  501         if (rw == FWRITE)
  502                 return 1;       /* heh. */
  503 
  504         s = splhigh();
  505         if (random_state.entropy_count >= 8)
  506                 ret = 1;
  507         else {
  508                 selrecord(p, &random_state.rsel);
  509                 ret = 0;
  510         }
  511         splx(s);
  512 
  513         return ret;
  514 }
  515 

Cache object: 5010cd9a2c41227be1b1e5b9d92aebef


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