CTC++ Coverage Report - Execution Profile    #371/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: drivers/char/hw_random.c
Instrumentation mode: function-decision-multicondition
TER: 5 % ( 7/144)

Start/ End/    
True False - Line Source

  1 /*
  2         Added support for the AMD Geode LX RNG
  3    (c) Copyright 2004-2005 Advanced Micro Devices, Inc.
  4 
  5    derived from
  6 
  7     Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
  8    (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
  9  
  10     derived from
  11  
  12         Hardware driver for the AMD 768 Random Number Generator (RNG)
  13         (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
  14 
  15     derived from
  16  
  17    Hardware driver for Intel i810 Random Number Generator (RNG)
  18    Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
  19    Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
  20 
  21    Please read Documentation/hw_random.txt for details on use.
  22 
  23    ----------------------------------------------------------
  24    This software may be used and distributed according to the terms
  25         of the GNU General Public License, incorporated herein by reference.
  26 
  27  */
  28 
  29 
  30 #include <linux/module.h>
  31 #include <linux/kernel.h>
  32 #include <linux/fs.h>
  33 #include <linux/init.h>
  34 #include <linux/pci.h>
  35 #include <linux/interrupt.h>
  36 #include <linux/spinlock.h>
  37 #include <linux/random.h>
  38 #include <linux/miscdevice.h>
  39 #include <linux/smp_lock.h>
  40 #include <linux/mm.h>
  41 #include <linux/delay.h>
  42 
  43 #ifdef __i386__
  44 #include <asm/msr.h>
  45 #include <asm/cpufeature.h>
  46 #endif
  47 
  48 #include <asm/io.h>
  49 #include <asm/uaccess.h>
  50 
  51 
  52 /*
  53  * core module and version information
  54  */
  55 #define RNG_VERSION "1.0.0"
  56 #define RNG_MODULE_NAME "hw_random"
  57 #define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
  58 #define PFX RNG_MODULE_NAME ": "
  59 
  60 
  61 /*
  62  * debugging macros
  63  */
  64 
  65 /* pr_debug() collapses to a no-op if DEBUG is not defined */
  66 #define DPRINTK(fmt, args...) pr_debug(PFX "%s: " fmt, __FUNCTION__ , ## args)
  67 
  68 
  69 #undef RNG_NDEBUG        /* define to enable lightweight runtime checks */
  70 #ifdef RNG_NDEBUG
  71 #define assert(expr)                     \
  72       if(!(expr)) {                  \
  73       printk(KERN_DEBUG PFX "Assertion failed! %s,%s,%s,"   \
  74       "line=%d\n", #expr, __FILE__, __FUNCTION__, __LINE__);   \
  75       }
  76 #else
  77 #define assert(expr)
  78 #endif
  79 
  80 #define RNG_MISCDEV_MINOR      183 /* official */
  81 
  82 static int rng_dev_open (struct inode *inode, struct file *filp);
  83 static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
  84             loff_t * offp);
  85 
  86 static int __init intel_init (struct pci_dev *dev);
  87 static void intel_cleanup(void);
  88 static unsigned int intel_data_present (void);
  89 static u32 intel_data_read (void);
  90 
  91 static int __init amd_init (struct pci_dev *dev);
  92 static void amd_cleanup(void);
  93 static unsigned int amd_data_present (void);
  94 static u32 amd_data_read (void);
  95 
  96 #ifdef __i386__
  97 static int __init via_init(struct pci_dev *dev);
  98 static void via_cleanup(void);
  99 static unsigned int via_data_present (void);
  100 static u32 via_data_read (void);
  101 #endif
  102 
  103 static int __init geode_init(struct pci_dev *dev);
  104 static void geode_cleanup(void);
  105 static unsigned int geode_data_present (void);
  106 static u32 geode_data_read (void);
  107 
  108 struct rng_operations {
  109    int (*init) (struct pci_dev *dev);
  110    void (*cleanup) (void);
  111    unsigned int (*data_present) (void);
  112    u32 (*data_read) (void);
  113    unsigned int n_bytes; /* number of bytes per ->data_read */
  114 };
  115 static struct rng_operations *rng_ops;
  116 
  117 static struct file_operations rng_chrdev_ops = {
  118    .owner      = THIS_MODULE,
  119    .open      = rng_dev_open,
  120    .read      = rng_dev_read,
  121 };
  122 
  123 
  124 static struct miscdevice rng_miscdev = {
  125    RNG_MISCDEV_MINOR,
  126    RNG_MODULE_NAME,
  127    &rng_chrdev_ops,
  128 };
  129 
  130 enum {
  131    rng_hw_none,
  132    rng_hw_intel,
  133    rng_hw_amd,
  134 #ifdef __i386__
  135    rng_hw_via,
  136 #endif
  137    rng_hw_geode,
  138 };
  139 
  140 static struct rng_operations rng_vendor_ops[] = {
  141    /* rng_hw_none */
  142    { },
  143 
  144    /* rng_hw_intel */
  145    { intel_init, intel_cleanup, intel_data_present,
  146      intel_data_read, 1 },
  147 
  148    /* rng_hw_amd */
  149    { amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 },
  150 
  151 #ifdef __i386__
  152    /* rng_hw_via */
  153    { via_init, via_cleanup, via_data_present, via_data_read, 1 },
  154 #endif
  155 
  156    /* rng_hw_geode */
  157    { geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 }
  158 };
  159 
  160 /*
  161  * Data for PCI driver interface
  162  *
  163  * This data only exists for exporting the supported
  164  * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
  165  * register a pci_driver, because someone else might one day
  166  * want to register another driver on the same PCI id.
  167  */
  168 static struct pci_device_id rng_pci_tbl[] = {
  169    { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
  170    { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
  171 
  172    { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
  173    { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
  174    { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
  175    { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
  176    { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
  177    { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
  178 
  179    { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES,
  180      PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_geode },
  181 
  182    { 0, },   /* terminate list */
  183 };
  184 MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
  185 
  186 
  187 /***********************************************************************
  188  *
  189  * Intel RNG operations
  190  *
  191  */
  192 
  193 /*
  194  * RNG registers (offsets from rng_mem)
  195  */
  196 #define INTEL_RNG_HW_STATUS         0
  197 #define         INTEL_RNG_PRESENT      0x40
  198 #define         INTEL_RNG_ENABLED      0x01
  199 #define INTEL_RNG_STATUS         1
  200 #define         INTEL_RNG_DATA_PRESENT      0x01
  201 #define INTEL_RNG_DATA            2
  202 
  203 /*
  204  * Magic address at which Intel PCI bridges locate the RNG
  205  */
  206 #define INTEL_RNG_ADDR            0xFFBC015F
  207 #define INTEL_RNG_ADDR_LEN         3
  208 
  209 /* token to our ioremap'd RNG register area */
  210 static void __iomem *rng_mem;
  211 
 
- 212 static inline u8 intel_hwstatus (void)
  213 {
  214    assert (rng_mem != NULL);
 - 215    return readb (rng_mem + INTEL_RNG_HW_STATUS);
  216 }
  217 
 
- 218 static inline u8 intel_hwstatus_set (u8 hw_status)
  219 {
  220    assert (rng_mem != NULL);
  221    writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS);
 - 222    return intel_hwstatus ();
  223 }
  224 
 
- 225 static unsigned int intel_data_present(void)
  226 {
  227    assert (rng_mem != NULL);
  228 
    229    return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ?
- 229 ternary-?: ( __readb ( rng_mem + 1 ) & 0x01 )
 - 230       1 : 0;
  231 }
  232 
 
- 233 static u32 intel_data_read(void)
  234 {
  235    assert (rng_mem != NULL);
  236 
 - 237    return readb (rng_mem + INTEL_RNG_DATA);
  238 }
  239 
 
- 240 static int __init intel_init (struct pci_dev *dev)
  241 {
  242    int rc;
  243    u8 hw_status;
  244 
    245    DPRINTK ("ENTER\n");
- 245 do-while (0)
  246 
  247    rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
- 248    if (rng_mem == NULL) {
  249       printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
  250       rc = -EBUSY;
 - 251       goto err_out;
  252    }
  253 
  254    /* Check for Intel 82802 */
  255    hw_status = intel_hwstatus ();
- 256    if ((hw_status & INTEL_RNG_PRESENT) == 0) {
  257       printk (KERN_ERR PFX "RNG not detected\n");
  258       rc = -ENODEV;
 - 259       goto err_out_free_map;
  260    }
  261 
  262    /* turn RNG h/w on, if it's off */
- 263    if ((hw_status & INTEL_RNG_ENABLED) == 0)
  264       hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED);
- 265    if ((hw_status & INTEL_RNG_ENABLED) == 0) {
  266       printk (KERN_ERR PFX "cannot enable RNG, aborting\n");
  267       rc = -EIO;
 - 268       goto err_out_free_map;
  269    }
  270 
    271    DPRINTK ("EXIT, returning 0\n");
- 271 do-while (0)
 - 272    return 0;
  273 
  274 err_out_free_map:
  275    iounmap (rng_mem);
  276    rng_mem = NULL;
  277 err_out:
    278    DPRINTK ("EXIT, returning %d\n", rc);
- 278 do-while (0)
 - 279    return rc;
  280 }
  281 
 
- 282 static void intel_cleanup(void)
  283 {
  284    u8 hw_status;
  285 
  286    hw_status = intel_hwstatus ();
- 287    if (hw_status & INTEL_RNG_ENABLED)
  288       intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED);
    289    else
  290       printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
  291    iounmap(rng_mem);
  292    rng_mem = NULL;
  293 }
  294 
  295 /***********************************************************************
  296  *
  297  * AMD RNG operations
  298  *
  299  */
  300 
  301 static u32 pmbase;         /* PMxx I/O base */
  302 static struct pci_dev *amd_dev;
  303 
 
- 304 static unsigned int amd_data_present (void)
  305 {
 - 306          return inl(pmbase + 0xF4) & 1;
  307 }
  308 
  309 
 
- 310 static u32 amd_data_read (void)
  311 {
 - 312    return inl(pmbase + 0xF0);
  313 }
  314 
 
- 315 static int __init amd_init (struct pci_dev *dev)
  316 {
  317    int rc;
  318    u8 rnen;
  319 
    320    DPRINTK ("ENTER\n");
- 320 do-while (0)
  321 
  322    pci_read_config_dword(dev, 0x58, &pmbase);
  323 
  324    pmbase &= 0x0000FF00;
  325 
- 326    if (pmbase == 0)
  327    {
  328       printk (KERN_ERR PFX "power management base not set\n");
  329       rc = -EIO;
 - 330       goto err_out;
  331    }
  332 
  333    pci_read_config_byte(dev, 0x40, &rnen);
  334    rnen |= (1 << 7);   /* RNG on */
  335    pci_write_config_byte(dev, 0x40, rnen);
  336 
  337    pci_read_config_byte(dev, 0x41, &rnen);
  338    rnen |= (1 << 7);   /* PMIO enable */
  339    pci_write_config_byte(dev, 0x41, rnen);
  340 
  341    pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n",
  342          pmbase);
  343 
  344    amd_dev = dev;
  345 
    346    DPRINTK ("EXIT, returning 0\n");
- 346 do-while (0)
 - 347    return 0;
  348 
  349 err_out:
    350    DPRINTK ("EXIT, returning %d\n", rc);
- 350 do-while (0)
 - 351    return rc;
  352 }
  353 
 
- 354 static void amd_cleanup(void)
  355 {
  356    u8 rnen;
  357 
  358    pci_read_config_byte(amd_dev, 0x40, &rnen);
  359    rnen &= ~(1 << 7);   /* RNG off */
  360    pci_write_config_byte(amd_dev, 0x40, rnen);
  361 
  362    /* FIXME: twiddle pmio, also? */
  363 }
  364 
  365 #ifdef __i386__
  366 /***********************************************************************
  367  *
  368  * VIA RNG operations
  369  *
  370  */
  371 
  372 enum {
  373    VIA_STRFILT_CNT_SHIFT   = 16,
  374    VIA_STRFILT_FAIL   = (1 << 15),
  375    VIA_STRFILT_ENABLE   = (1 << 14),
  376    VIA_RAWBITS_ENABLE   = (1 << 13),
  377    VIA_RNG_ENABLE      = (1 << 6),
  378    VIA_XSTORE_CNT_MASK   = 0x0F,
  379 
  380    VIA_RNG_CHUNK_8      = 0x00,   /* 64 rand bits, 64 stored bits */
  381    VIA_RNG_CHUNK_4      = 0x01,   /* 32 rand bits, 32 stored bits */
  382    VIA_RNG_CHUNK_4_MASK   = 0xFFFFFFFF,
  383    VIA_RNG_CHUNK_2      = 0x02,   /* 16 rand bits, 32 stored bits */
  384    VIA_RNG_CHUNK_2_MASK   = 0xFFFF,
  385    VIA_RNG_CHUNK_1      = 0x03,   /* 8 rand bits, 32 stored bits */
  386    VIA_RNG_CHUNK_1_MASK   = 0xFF,
  387 };
  388 
  389 static u32 via_rng_datum;
  390 
  391 /*
  392  * Investigate using the 'rep' prefix to obtain 32 bits of random data
  393  * in one insn.  The upside is potentially better performance.  The
  394  * downside is that the instruction becomes no longer atomic.  Due to
  395  * this, just like familiar issues with /dev/random itself, the worst
  396  * case of a 'rep xstore' could potentially pause a cpu for an
  397  * unreasonably long time.  In practice, this condition would likely
  398  * only occur when the hardware is failing.  (or so we hope :))
  399  *
  400  * Another possible performance boost may come from simply buffering
  401  * until we have 4 bytes, thus returning a u32 at a time,
  402  * instead of the current u8-at-a-time.
  403  */
  404 
  405 static inline u32 xstore(u32 *addr, u32 edx_in)
  406 {
  407    u32 eax_out;
  408 
  409    asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
  410       :"=m"(*addr), "=a"(eax_out)
  411       :"D"(addr), "d"(edx_in));
  412 
  413    return eax_out;
  414 }
  415 
  416 static unsigned int via_data_present(void)
  417 {
  418    u32 bytes_out;
  419 
  420    /* We choose the recommended 1-byte-per-instruction RNG rate,
  421     * for greater randomness at the expense of speed.  Larger
  422     * values 2, 4, or 8 bytes-per-instruction yield greater
  423     * speed at lesser randomness.
  424     *
  425     * If you change this to another VIA_CHUNK_n, you must also
  426     * change the ->n_bytes values in rng_vendor_ops[] tables.
  427     * VIA_CHUNK_8 requires further code changes.
  428     *
  429     * A copy of MSR_VIA_RNG is placed in eax_out when xstore
  430     * completes.
  431     */
  432    via_rng_datum = 0; /* paranoia, not really necessary */
  433    bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK;
  434    if (bytes_out == 0)
  435       return 0;
  436 
  437    return 1;
  438 }
  439 
  440 static u32 via_data_read(void)
  441 {
  442    return via_rng_datum;
  443 }
  444 
  445 static int __init via_init(struct pci_dev *dev)
  446 {
  447    u32 lo, hi, old_lo;
  448 
  449    /* Control the RNG via MSR.  Tread lightly and pay very close
  450     * close attention to values written, as the reserved fields
  451     * are documented to be "undefined and unpredictable"; but it
  452     * does not say to write them as zero, so I make a guess that
  453     * we restore the values we find in the register.
  454     */
  455    rdmsr(MSR_VIA_RNG, lo, hi);
  456 
  457    old_lo = lo;
  458    lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
  459    lo &= ~VIA_XSTORE_CNT_MASK;
  460    lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
  461    lo |= VIA_RNG_ENABLE;
  462 
  463    if (lo != old_lo)
  464       wrmsr(MSR_VIA_RNG, lo, hi);
  465 
  466    /* perhaps-unnecessary sanity check; remove after testing if
  467       unneeded */
  468    rdmsr(MSR_VIA_RNG, lo, hi);
  469    if ((lo & VIA_RNG_ENABLE) == 0) {
  470       printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n");
  471       return -ENODEV;
  472    }
  473 
  474    return 0;
  475 }
  476 
  477 static void via_cleanup(void)
  478 {
  479    /* do nothing */
  480 }
  481 #endif
  482 
  483 /***********************************************************************
  484  *
  485  * AMD Geode RNG operations
  486  *
  487  */
  488 
  489 static void __iomem *geode_rng_base = NULL;
  490 
  491 #define GEODE_RNG_DATA_REG   0x50
  492 #define GEODE_RNG_STATUS_REG 0x54
  493 
 
- 494 static u32 geode_data_read(void)
  495 {
  496    u32 val;
  497 
  498    assert(geode_rng_base != NULL);
  499    val = readl(geode_rng_base + GEODE_RNG_DATA_REG);
 - 500    return val;
  501 }
  502 
 
- 503 static unsigned int geode_data_present(void)
  504 {
  505    u32 val;
  506 
  507    assert(geode_rng_base != NULL);
  508    val = readl(geode_rng_base + GEODE_RNG_STATUS_REG);
 - 509    return val;
  510 }
  511 
 
- 512 static void geode_cleanup(void)
  513 {
  514    iounmap(geode_rng_base);
  515      geode_rng_base = NULL;
  516 }
  517 
 
- 518 static int geode_init(struct pci_dev *dev)
  519 {
  520    unsigned long rng_base = pci_resource_start(dev, 0);
  521 
- 522    if (rng_base == 0)
 - 523       return 1;
  524 
  525    geode_rng_base = ioremap(rng_base, 0x58);
  526 
- 527    if (geode_rng_base == NULL) {
  528       printk(KERN_ERR PFX "Cannot ioremap RNG memory\n");
 - 529       return -EBUSY;
  530    }
  531 
 - 532    return 0;
  533 }
  534 
  535 /***********************************************************************
  536  *
  537  * /dev/hwrandom character device handling (major 10, minor 183)
  538  *
  539  */
  540 
 
- 541 static int rng_dev_open (struct inode *inode, struct file *filp)
  542 {
  543    /* enforce read-only access to this chrdev */
- 544    if ((filp->f_mode & FMODE_READ) == 0)
 - 545       return -EINVAL;
- 546    if (filp->f_mode & FMODE_WRITE)
 - 547       return -EINVAL;
  548 
 - 549    return 0;
  550 }
  551 
  552 
 
- 553 static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
  554             loff_t * offp)
  555 {
  556    static DEFINE_SPINLOCK(rng_lock);
  557    unsigned int have_data;
  558    u32 data = 0;
  559    ssize_t ret = 0;
  560 
- 561    while (size) {
    562       spin_lock(&rng_lock);
    562     do
- 562     do-while (0)
- 562   do-while (0)
  563 
  564       have_data = 0;
- 565       if (rng_ops->data_present()) {
  566          data = rng_ops->data_read();
  567          have_data = rng_ops->n_bytes;
  568       }
  569 
    570       spin_unlock (&rng_lock);
    570     do
- 570     do-while (0)
- 570   do-while (0)
  571 
- 572       while (have_data && size) {
 - 572     T && T
 - 572     T && F
 - 572     F && _
- 573          if (put_user((u8)data, buf++)) {
  574             ret = ret ? : -EFAULT;
 - 575             break;
  576          }
  577          size--;
  578          ret++;
  579          have_data--;
  580          data>>=8;
  581       }
  582 
- 583       if (filp->f_flags & O_NONBLOCK)
 - 584          return ret ? : -EAGAIN;<