diff options
author | Michael Ellerman <michael@ellerman.id.au> | 2015-03-20 05:39:41 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2015-04-21 09:21:29 -0400 |
commit | e928e9cb3601ce240189bfea05b67ebd391c85ae (patch) | |
tree | d76d6501bea8ffe04a448e5a5660d8926f22b3b4 /arch/powerpc | |
parent | 99342cf8044420eebdf9297ca03a14cb6a7085a1 (diff) |
KVM: PPC: Book3S HV: Add fast real-mode H_RANDOM implementation.
Some PowerNV systems include a hardware random-number generator.
This HWRNG is present on POWER7+ and POWER8 chips and is capable of
generating one 64-bit random number every microsecond. The random
numbers are produced by sampling a set of 64 unstable high-frequency
oscillators and are almost completely entropic.
PAPR defines an H_RANDOM hypercall which guests can use to obtain one
64-bit random sample from the HWRNG. This adds a real-mode
implementation of the H_RANDOM hypercall. This hypercall was
implemented in real mode because the latency of reading the HWRNG is
generally small compared to the latency of a guest exit and entry for
all the threads in the same virtual core.
Userspace can detect the presence of the HWRNG and the H_RANDOM
implementation by querying the KVM_CAP_PPC_HWRNG capability. The
H_RANDOM hypercall implementation will only be invoked when the guest
does an H_RANDOM hypercall if userspace first enables the in-kernel
H_RANDOM implementation using the KVM_CAP_PPC_ENABLE_HCALL capability.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/archrandom.h | 11 | ||||
-rw-r--r-- | arch/powerpc/include/asm/kvm_ppc.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_builtin.c | 15 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rmhandlers.S | 115 | ||||
-rw-r--r-- | arch/powerpc/kvm/powerpc.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/rng.c | 29 |
6 files changed, 173 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/archrandom.h b/arch/powerpc/include/asm/archrandom.h index bde531103638..0cc6eedc4780 100644 --- a/arch/powerpc/include/asm/archrandom.h +++ b/arch/powerpc/include/asm/archrandom.h | |||
@@ -30,8 +30,6 @@ static inline int arch_has_random(void) | |||
30 | return !!ppc_md.get_random_long; | 30 | return !!ppc_md.get_random_long; |
31 | } | 31 | } |
32 | 32 | ||
33 | int powernv_get_random_long(unsigned long *v); | ||
34 | |||
35 | static inline int arch_get_random_seed_long(unsigned long *v) | 33 | static inline int arch_get_random_seed_long(unsigned long *v) |
36 | { | 34 | { |
37 | return 0; | 35 | return 0; |
@@ -47,4 +45,13 @@ static inline int arch_has_random_seed(void) | |||
47 | 45 | ||
48 | #endif /* CONFIG_ARCH_RANDOM */ | 46 | #endif /* CONFIG_ARCH_RANDOM */ |
49 | 47 | ||
48 | #ifdef CONFIG_PPC_POWERNV | ||
49 | int powernv_hwrng_present(void); | ||
50 | int powernv_get_random_long(unsigned long *v); | ||
51 | int powernv_get_random_real_mode(unsigned long *v); | ||
52 | #else | ||
53 | static inline int powernv_hwrng_present(void) { return 0; } | ||
54 | static inline int powernv_get_random_real_mode(unsigned long *v) { return 0; } | ||
55 | #endif | ||
56 | |||
50 | #endif /* _ASM_POWERPC_ARCHRANDOM_H */ | 57 | #endif /* _ASM_POWERPC_ARCHRANDOM_H */ |
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 46bf652c9169..b8475daad884 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h | |||
@@ -302,6 +302,8 @@ static inline bool is_kvmppc_hv_enabled(struct kvm *kvm) | |||
302 | return kvm->arch.kvm_ops == kvmppc_hv_ops; | 302 | return kvm->arch.kvm_ops == kvmppc_hv_ops; |
303 | } | 303 | } |
304 | 304 | ||
305 | extern int kvmppc_hwrng_present(void); | ||
306 | |||
305 | /* | 307 | /* |
306 | * Cuts out inst bits with ordering according to spec. | 308 | * Cuts out inst bits with ordering according to spec. |
307 | * That means the leftmost bit is zero. All given bits are included. | 309 | * That means the leftmost bit is zero. All given bits are included. |
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index 1f083ff8a61a..1954a1c4b1f9 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/cputable.h> | 21 | #include <asm/cputable.h> |
22 | #include <asm/kvm_ppc.h> | 22 | #include <asm/kvm_ppc.h> |
23 | #include <asm/kvm_book3s.h> | 23 | #include <asm/kvm_book3s.h> |
24 | #include <asm/archrandom.h> | ||
24 | 25 | ||
25 | #define KVM_CMA_CHUNK_ORDER 18 | 26 | #define KVM_CMA_CHUNK_ORDER 18 |
26 | 27 | ||
@@ -169,3 +170,17 @@ int kvmppc_hcall_impl_hv_realmode(unsigned long cmd) | |||
169 | return 0; | 170 | return 0; |
170 | } | 171 | } |
171 | EXPORT_SYMBOL_GPL(kvmppc_hcall_impl_hv_realmode); | 172 | EXPORT_SYMBOL_GPL(kvmppc_hcall_impl_hv_realmode); |
173 | |||
174 | int kvmppc_hwrng_present(void) | ||
175 | { | ||
176 | return powernv_hwrng_present(); | ||
177 | } | ||
178 | EXPORT_SYMBOL_GPL(kvmppc_hwrng_present); | ||
179 | |||
180 | long kvmppc_h_random(struct kvm_vcpu *vcpu) | ||
181 | { | ||
182 | if (powernv_get_random_real_mode(&vcpu->arch.gpr[4])) | ||
183 | return H_SUCCESS; | ||
184 | |||
185 | return H_HARDWARE; | ||
186 | } | ||
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 6cbf1630cb70..0814ca122fcd 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S | |||
@@ -1839,6 +1839,121 @@ hcall_real_table: | |||
1839 | .long 0 /* 0x12c */ | 1839 | .long 0 /* 0x12c */ |
1840 | .long 0 /* 0x130 */ | 1840 | .long 0 /* 0x130 */ |
1841 | .long DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table | 1841 | .long DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table |
1842 | .long 0 /* 0x138 */ | ||
1843 | .long 0 /* 0x13c */ | ||
1844 | .long 0 /* 0x140 */ | ||
1845 | .long 0 /* 0x144 */ | ||
1846 | .long 0 /* 0x148 */ | ||
1847 | .long 0 /* 0x14c */ | ||
1848 | .long 0 /* 0x150 */ | ||
1849 | .long 0 /* 0x154 */ | ||
1850 | .long 0 /* 0x158 */ | ||
1851 | .long 0 /* 0x15c */ | ||
1852 | .long 0 /* 0x160 */ | ||
1853 | .long 0 /* 0x164 */ | ||
1854 | .long 0 /* 0x168 */ | ||
1855 | .long 0 /* 0x16c */ | ||
1856 | .long 0 /* 0x170 */ | ||
1857 | .long 0 /* 0x174 */ | ||
1858 | .long 0 /* 0x178 */ | ||
1859 | .long 0 /* 0x17c */ | ||
1860 | .long 0 /* 0x180 */ | ||
1861 | .long 0 /* 0x184 */ | ||
1862 | .long 0 /* 0x188 */ | ||
1863 | .long 0 /* 0x18c */ | ||
1864 | .long 0 /* 0x190 */ | ||
1865 | .long 0 /* 0x194 */ | ||
1866 | .long 0 /* 0x198 */ | ||
1867 | .long 0 /* 0x19c */ | ||
1868 | .long 0 /* 0x1a0 */ | ||
1869 | .long 0 /* 0x1a4 */ | ||
1870 | .long 0 /* 0x1a8 */ | ||
1871 | .long 0 /* 0x1ac */ | ||
1872 | .long 0 /* 0x1b0 */ | ||
1873 | .long 0 /* 0x1b4 */ | ||
1874 | .long 0 /* 0x1b8 */ | ||
1875 | .long 0 /* 0x1bc */ | ||
1876 | .long 0 /* 0x1c0 */ | ||
1877 | .long 0 /* 0x1c4 */ | ||
1878 | .long 0 /* 0x1c8 */ | ||
1879 | .long 0 /* 0x1cc */ | ||
1880 | .long 0 /* 0x1d0 */ | ||
1881 | .long 0 /* 0x1d4 */ | ||
1882 | .long 0 /* 0x1d8 */ | ||
1883 | .long 0 /* 0x1dc */ | ||
1884 | .long 0 /* 0x1e0 */ | ||
1885 | .long 0 /* 0x1e4 */ | ||
1886 | .long 0 /* 0x1e8 */ | ||
1887 | .long 0 /* 0x1ec */ | ||
1888 | .long 0 /* 0x1f0 */ | ||
1889 | .long 0 /* 0x1f4 */ | ||
1890 | .long 0 /* 0x1f8 */ | ||
1891 | .long 0 /* 0x1fc */ | ||
1892 | .long 0 /* 0x200 */ | ||
1893 | .long 0 /* 0x204 */ | ||
1894 | .long 0 /* 0x208 */ | ||
1895 | .long 0 /* 0x20c */ | ||
1896 | .long 0 /* 0x210 */ | ||
1897 | .long 0 /* 0x214 */ | ||
1898 | .long 0 /* 0x218 */ | ||
1899 | .long 0 /* 0x21c */ | ||
1900 | .long 0 /* 0x220 */ | ||
1901 | .long 0 /* 0x224 */ | ||
1902 | .long 0 /* 0x228 */ | ||
1903 | .long 0 /* 0x22c */ | ||
1904 | .long 0 /* 0x230 */ | ||
1905 | .long 0 /* 0x234 */ | ||
1906 | .long 0 /* 0x238 */ | ||
1907 | .long 0 /* 0x23c */ | ||
1908 | .long 0 /* 0x240 */ | ||
1909 | .long 0 /* 0x244 */ | ||
1910 | .long 0 /* 0x248 */ | ||
1911 | .long 0 /* 0x24c */ | ||
1912 | .long 0 /* 0x250 */ | ||
1913 | .long 0 /* 0x254 */ | ||
1914 | .long 0 /* 0x258 */ | ||
1915 | .long 0 /* 0x25c */ | ||
1916 | .long 0 /* 0x260 */ | ||
1917 | .long 0 /* 0x264 */ | ||
1918 | .long 0 /* 0x268 */ | ||
1919 | .long 0 /* 0x26c */ | ||
1920 | .long 0 /* 0x270 */ | ||
1921 | .long 0 /* 0x274 */ | ||
1922 | .long 0 /* 0x278 */ | ||
1923 | .long 0 /* 0x27c */ | ||
1924 | .long 0 /* 0x280 */ | ||
1925 | .long 0 /* 0x284 */ | ||
1926 | .long 0 /* 0x288 */ | ||
1927 | .long 0 /* 0x28c */ | ||
1928 | .long 0 /* 0x290 */ | ||
1929 | .long 0 /* 0x294 */ | ||
1930 | .long 0 /* 0x298 */ | ||
1931 | .long 0 /* 0x29c */ | ||
1932 | .long 0 /* 0x2a0 */ | ||
1933 | .long 0 /* 0x2a4 */ | ||
1934 | .long 0 /* 0x2a8 */ | ||
1935 | .long 0 /* 0x2ac */ | ||
1936 | .long 0 /* 0x2b0 */ | ||
1937 | .long 0 /* 0x2b4 */ | ||
1938 | .long 0 /* 0x2b8 */ | ||
1939 | .long 0 /* 0x2bc */ | ||
1940 | .long 0 /* 0x2c0 */ | ||
1941 | .long 0 /* 0x2c4 */ | ||
1942 | .long 0 /* 0x2c8 */ | ||
1943 | .long 0 /* 0x2cc */ | ||
1944 | .long 0 /* 0x2d0 */ | ||
1945 | .long 0 /* 0x2d4 */ | ||
1946 | .long 0 /* 0x2d8 */ | ||
1947 | .long 0 /* 0x2dc */ | ||
1948 | .long 0 /* 0x2e0 */ | ||
1949 | .long 0 /* 0x2e4 */ | ||
1950 | .long 0 /* 0x2e8 */ | ||
1951 | .long 0 /* 0x2ec */ | ||
1952 | .long 0 /* 0x2f0 */ | ||
1953 | .long 0 /* 0x2f4 */ | ||
1954 | .long 0 /* 0x2f8 */ | ||
1955 | .long 0 /* 0x2fc */ | ||
1956 | .long DOTSYM(kvmppc_h_random) - hcall_real_table | ||
1842 | .globl hcall_real_table_end | 1957 | .globl hcall_real_table_end |
1843 | hcall_real_table_end: | 1958 | hcall_real_table_end: |
1844 | 1959 | ||
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 24bfe401373e..55a4763d6d11 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -529,6 +529,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) | |||
529 | case KVM_CAP_PPC_RMA: | 529 | case KVM_CAP_PPC_RMA: |
530 | r = 0; | 530 | r = 0; |
531 | break; | 531 | break; |
532 | case KVM_CAP_PPC_HWRNG: | ||
533 | r = kvmppc_hwrng_present(); | ||
534 | break; | ||
532 | #endif | 535 | #endif |
533 | case KVM_CAP_SYNC_MMU: | 536 | case KVM_CAP_SYNC_MMU: |
534 | #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE | 537 | #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE |
diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/powernv/rng.c index 80db43944afe..6eb808ff637e 100644 --- a/arch/powerpc/platforms/powernv/rng.c +++ b/arch/powerpc/platforms/powernv/rng.c | |||
@@ -24,12 +24,22 @@ | |||
24 | 24 | ||
25 | struct powernv_rng { | 25 | struct powernv_rng { |
26 | void __iomem *regs; | 26 | void __iomem *regs; |
27 | void __iomem *regs_real; | ||
27 | unsigned long mask; | 28 | unsigned long mask; |
28 | }; | 29 | }; |
29 | 30 | ||
30 | static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng); | 31 | static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng); |
31 | 32 | ||
32 | 33 | ||
34 | int powernv_hwrng_present(void) | ||
35 | { | ||
36 | struct powernv_rng *rng; | ||
37 | |||
38 | rng = get_cpu_var(powernv_rng); | ||
39 | put_cpu_var(rng); | ||
40 | return rng != NULL; | ||
41 | } | ||
42 | |||
33 | static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) | 43 | static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) |
34 | { | 44 | { |
35 | unsigned long parity; | 45 | unsigned long parity; |
@@ -46,6 +56,17 @@ static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val) | |||
46 | return val; | 56 | return val; |
47 | } | 57 | } |
48 | 58 | ||
59 | int powernv_get_random_real_mode(unsigned long *v) | ||
60 | { | ||
61 | struct powernv_rng *rng; | ||
62 | |||
63 | rng = raw_cpu_read(powernv_rng); | ||
64 | |||
65 | *v = rng_whiten(rng, in_rm64(rng->regs_real)); | ||
66 | |||
67 | return 1; | ||
68 | } | ||
69 | |||
49 | int powernv_get_random_long(unsigned long *v) | 70 | int powernv_get_random_long(unsigned long *v) |
50 | { | 71 | { |
51 | struct powernv_rng *rng; | 72 | struct powernv_rng *rng; |
@@ -80,12 +101,20 @@ static __init void rng_init_per_cpu(struct powernv_rng *rng, | |||
80 | static __init int rng_create(struct device_node *dn) | 101 | static __init int rng_create(struct device_node *dn) |
81 | { | 102 | { |
82 | struct powernv_rng *rng; | 103 | struct powernv_rng *rng; |
104 | struct resource res; | ||
83 | unsigned long val; | 105 | unsigned long val; |
84 | 106 | ||
85 | rng = kzalloc(sizeof(*rng), GFP_KERNEL); | 107 | rng = kzalloc(sizeof(*rng), GFP_KERNEL); |
86 | if (!rng) | 108 | if (!rng) |
87 | return -ENOMEM; | 109 | return -ENOMEM; |
88 | 110 | ||
111 | if (of_address_to_resource(dn, 0, &res)) { | ||
112 | kfree(rng); | ||
113 | return -ENXIO; | ||
114 | } | ||
115 | |||
116 | rng->regs_real = (void __iomem *)res.start; | ||
117 | |||
89 | rng->regs = of_iomap(dn, 0); | 118 | rng->regs = of_iomap(dn, 0); |
90 | if (!rng->regs) { | 119 | if (!rng->regs) { |
91 | kfree(rng); | 120 | kfree(rng); |