linux/arch/x86/include/asm/archrandom.h
<<
>>
Prefs
   1/*
   2 * This file is part of the Linux kernel.
   3 *
   4 * Copyright (c) 2011-2014, Intel Corporation
   5 * Authors: Fenghua Yu <fenghua.yu@intel.com>,
   6 *          H. Peter Anvin <hpa@linux.intel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms and conditions of the GNU General Public License,
  10 * version 2, as published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope it will be useful, but WITHOUT
  13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15 * more details.
  16 *
  17 * You should have received a copy of the GNU General Public License along with
  18 * this program; if not, write to the Free Software Foundation, Inc.,
  19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  20 *
  21 */
  22
  23#ifndef ASM_X86_ARCHRANDOM_H
  24#define ASM_X86_ARCHRANDOM_H
  25
  26#include <asm/processor.h>
  27#include <asm/cpufeature.h>
  28#include <asm/alternative.h>
  29#include <asm/nops.h>
  30
  31#define RDRAND_RETRY_LOOPS      10
  32
  33#define RDRAND_INT      ".byte 0x0f,0xc7,0xf0"
  34#define RDSEED_INT      ".byte 0x0f,0xc7,0xf8"
  35#ifdef CONFIG_X86_64
  36# define RDRAND_LONG    ".byte 0x48,0x0f,0xc7,0xf0"
  37# define RDSEED_LONG    ".byte 0x48,0x0f,0xc7,0xf8"
  38#else
  39# define RDRAND_LONG    RDRAND_INT
  40# define RDSEED_LONG    RDSEED_INT
  41#endif
  42
  43#ifdef CONFIG_ARCH_RANDOM
  44
  45/* Instead of arch_get_random_long() when alternatives haven't run. */
  46static inline int rdrand_long(unsigned long *v)
  47{
  48        int ok;
  49        asm volatile("1: " RDRAND_LONG "\n\t"
  50                     "jc 2f\n\t"
  51                     "decl %0\n\t"
  52                     "jnz 1b\n\t"
  53                     "2:"
  54                     : "=r" (ok), "=a" (*v)
  55                     : "0" (RDRAND_RETRY_LOOPS));
  56        return ok;
  57}
  58
  59/* A single attempt at RDSEED */
  60static inline bool rdseed_long(unsigned long *v)
  61{
  62        unsigned char ok;
  63        asm volatile(RDSEED_LONG "\n\t"
  64                     "setc %0"
  65                     : "=qm" (ok), "=a" (*v));
  66        return ok;
  67}
  68
  69#define GET_RANDOM(name, type, rdrand, nop)                     \
  70static inline int name(type *v)                                 \
  71{                                                               \
  72        int ok;                                                 \
  73        alternative_io("movl $0, %0\n\t"                        \
  74                       nop,                                     \
  75                       "\n1: " rdrand "\n\t"                    \
  76                       "jc 2f\n\t"                              \
  77                       "decl %0\n\t"                            \
  78                       "jnz 1b\n\t"                             \
  79                       "2:",                                    \
  80                       X86_FEATURE_RDRAND,                      \
  81                       ASM_OUTPUT2("=r" (ok), "=a" (*v)),       \
  82                       "0" (RDRAND_RETRY_LOOPS));               \
  83        return ok;                                              \
  84}
  85
  86#define GET_SEED(name, type, rdseed, nop)                       \
  87static inline int name(type *v)                                 \
  88{                                                               \
  89        unsigned char ok;                                       \
  90        alternative_io("movb $0, %0\n\t"                        \
  91                       nop,                                     \
  92                       rdseed "\n\t"                            \
  93                       "setc %0",                               \
  94                       X86_FEATURE_RDSEED,                      \
  95                       ASM_OUTPUT2("=q" (ok), "=a" (*v)));      \
  96        return ok;                                              \
  97}
  98
  99#ifdef CONFIG_X86_64
 100
 101GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP5);
 102GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP4);
 103
 104GET_SEED(arch_get_random_seed_long, unsigned long, RDSEED_LONG, ASM_NOP5);
 105GET_SEED(arch_get_random_seed_int, unsigned int, RDSEED_INT, ASM_NOP4);
 106
 107#else
 108
 109GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP3);
 110GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3);
 111
 112GET_SEED(arch_get_random_seed_long, unsigned long, RDSEED_LONG, ASM_NOP4);
 113GET_SEED(arch_get_random_seed_int, unsigned int, RDSEED_INT, ASM_NOP4);
 114
 115#endif /* CONFIG_X86_64 */
 116
 117#define arch_has_random()       static_cpu_has(X86_FEATURE_RDRAND)
 118#define arch_has_random_seed()  static_cpu_has(X86_FEATURE_RDSEED)
 119
 120#else
 121
 122static inline int rdrand_long(unsigned long *v)
 123{
 124        return 0;
 125}
 126
 127static inline bool rdseed_long(unsigned long *v)
 128{
 129        return 0;
 130}
 131
 132#endif  /* CONFIG_ARCH_RANDOM */
 133
 134extern void x86_init_rdrand(struct cpuinfo_x86 *c);
 135
 136#endif /* ASM_X86_ARCHRANDOM_H */
 137