forked from mirrors/linux
		
	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>
This commit is contained in:
		
							parent
							
								
									99342cf804
								
							
						
					
					
						commit
						e928e9cb36
					
				
					 8 changed files with 191 additions and 2 deletions
				
			
		| 
						 | 
					@ -3573,3 +3573,20 @@ struct {
 | 
				
			||||||
@ar   - access register number
 | 
					@ar   - access register number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
KVM handlers should exit to userspace with rc = -EREMOTE.
 | 
					KVM handlers should exit to userspace with rc = -EREMOTE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					8. Other capabilities.
 | 
				
			||||||
 | 
					----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This section lists capabilities that give information about other
 | 
				
			||||||
 | 
					features of the KVM implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					8.1 KVM_CAP_PPC_HWRNG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Architectures: ppc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This capability, if KVM_CHECK_EXTENSION indicates that it is
 | 
				
			||||||
 | 
					available, means that that the kernel has an implementation of the
 | 
				
			||||||
 | 
					H_RANDOM hypercall backed by a hardware random-number generator.
 | 
				
			||||||
 | 
					If present, the kernel H_RANDOM handler can be enabled for guest use
 | 
				
			||||||
 | 
					with the KVM_CAP_PPC_ENABLE_HCALL capability.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,8 +30,6 @@ static inline int arch_has_random(void)
 | 
				
			||||||
	return !!ppc_md.get_random_long;
 | 
						return !!ppc_md.get_random_long;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int powernv_get_random_long(unsigned long *v);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int arch_get_random_seed_long(unsigned long *v)
 | 
					static inline int arch_get_random_seed_long(unsigned long *v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -47,4 +45,13 @@ static inline int arch_has_random_seed(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* CONFIG_ARCH_RANDOM */
 | 
					#endif /* CONFIG_ARCH_RANDOM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_PPC_POWERNV
 | 
				
			||||||
 | 
					int powernv_hwrng_present(void);
 | 
				
			||||||
 | 
					int powernv_get_random_long(unsigned long *v);
 | 
				
			||||||
 | 
					int powernv_get_random_real_mode(unsigned long *v);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static inline int powernv_hwrng_present(void) { return 0; }
 | 
				
			||||||
 | 
					static inline int powernv_get_random_real_mode(unsigned long *v) { return 0; }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_POWERPC_ARCHRANDOM_H */
 | 
					#endif /* _ASM_POWERPC_ARCHRANDOM_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -302,6 +302,8 @@ static inline bool is_kvmppc_hv_enabled(struct kvm *kvm)
 | 
				
			||||||
	return kvm->arch.kvm_ops == kvmppc_hv_ops;
 | 
						return kvm->arch.kvm_ops == kvmppc_hv_ops;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int kvmppc_hwrng_present(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Cuts out inst bits with ordering according to spec.
 | 
					 * Cuts out inst bits with ordering according to spec.
 | 
				
			||||||
 * That means the leftmost bit is zero. All given bits are included.
 | 
					 * That means the leftmost bit is zero. All given bits are included.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@
 | 
				
			||||||
#include <asm/cputable.h>
 | 
					#include <asm/cputable.h>
 | 
				
			||||||
#include <asm/kvm_ppc.h>
 | 
					#include <asm/kvm_ppc.h>
 | 
				
			||||||
#include <asm/kvm_book3s.h>
 | 
					#include <asm/kvm_book3s.h>
 | 
				
			||||||
 | 
					#include <asm/archrandom.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define KVM_CMA_CHUNK_ORDER	18
 | 
					#define KVM_CMA_CHUNK_ORDER	18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,3 +170,17 @@ int kvmppc_hcall_impl_hv_realmode(unsigned long cmd)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(kvmppc_hcall_impl_hv_realmode);
 | 
					EXPORT_SYMBOL_GPL(kvmppc_hcall_impl_hv_realmode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int kvmppc_hwrng_present(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return powernv_hwrng_present();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(kvmppc_hwrng_present);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					long kvmppc_h_random(struct kvm_vcpu *vcpu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (powernv_get_random_real_mode(&vcpu->arch.gpr[4]))
 | 
				
			||||||
 | 
							return H_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return H_HARDWARE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1839,6 +1839,121 @@ hcall_real_table:
 | 
				
			||||||
	.long	0		/* 0x12c */
 | 
						.long	0		/* 0x12c */
 | 
				
			||||||
	.long	0		/* 0x130 */
 | 
						.long	0		/* 0x130 */
 | 
				
			||||||
	.long	DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table
 | 
						.long	DOTSYM(kvmppc_h_set_xdabr) - hcall_real_table
 | 
				
			||||||
 | 
						.long	0		/* 0x138 */
 | 
				
			||||||
 | 
						.long	0		/* 0x13c */
 | 
				
			||||||
 | 
						.long	0		/* 0x140 */
 | 
				
			||||||
 | 
						.long	0		/* 0x144 */
 | 
				
			||||||
 | 
						.long	0		/* 0x148 */
 | 
				
			||||||
 | 
						.long	0		/* 0x14c */
 | 
				
			||||||
 | 
						.long	0		/* 0x150 */
 | 
				
			||||||
 | 
						.long	0		/* 0x154 */
 | 
				
			||||||
 | 
						.long	0		/* 0x158 */
 | 
				
			||||||
 | 
						.long	0		/* 0x15c */
 | 
				
			||||||
 | 
						.long	0		/* 0x160 */
 | 
				
			||||||
 | 
						.long	0		/* 0x164 */
 | 
				
			||||||
 | 
						.long	0		/* 0x168 */
 | 
				
			||||||
 | 
						.long	0		/* 0x16c */
 | 
				
			||||||
 | 
						.long	0		/* 0x170 */
 | 
				
			||||||
 | 
						.long	0		/* 0x174 */
 | 
				
			||||||
 | 
						.long	0		/* 0x178 */
 | 
				
			||||||
 | 
						.long	0		/* 0x17c */
 | 
				
			||||||
 | 
						.long	0		/* 0x180 */
 | 
				
			||||||
 | 
						.long	0		/* 0x184 */
 | 
				
			||||||
 | 
						.long	0		/* 0x188 */
 | 
				
			||||||
 | 
						.long	0		/* 0x18c */
 | 
				
			||||||
 | 
						.long	0		/* 0x190 */
 | 
				
			||||||
 | 
						.long	0		/* 0x194 */
 | 
				
			||||||
 | 
						.long	0		/* 0x198 */
 | 
				
			||||||
 | 
						.long	0		/* 0x19c */
 | 
				
			||||||
 | 
						.long	0		/* 0x1a0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1a4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1a8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1ac */
 | 
				
			||||||
 | 
						.long	0		/* 0x1b0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1b4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1b8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1bc */
 | 
				
			||||||
 | 
						.long	0		/* 0x1c0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1c4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1c8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1cc */
 | 
				
			||||||
 | 
						.long	0		/* 0x1d0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1d4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1d8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1dc */
 | 
				
			||||||
 | 
						.long	0		/* 0x1e0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1e4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1e8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1ec */
 | 
				
			||||||
 | 
						.long	0		/* 0x1f0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1f4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1f8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x1fc */
 | 
				
			||||||
 | 
						.long	0		/* 0x200 */
 | 
				
			||||||
 | 
						.long	0		/* 0x204 */
 | 
				
			||||||
 | 
						.long	0		/* 0x208 */
 | 
				
			||||||
 | 
						.long	0		/* 0x20c */
 | 
				
			||||||
 | 
						.long	0		/* 0x210 */
 | 
				
			||||||
 | 
						.long	0		/* 0x214 */
 | 
				
			||||||
 | 
						.long	0		/* 0x218 */
 | 
				
			||||||
 | 
						.long	0		/* 0x21c */
 | 
				
			||||||
 | 
						.long	0		/* 0x220 */
 | 
				
			||||||
 | 
						.long	0		/* 0x224 */
 | 
				
			||||||
 | 
						.long	0		/* 0x228 */
 | 
				
			||||||
 | 
						.long	0		/* 0x22c */
 | 
				
			||||||
 | 
						.long	0		/* 0x230 */
 | 
				
			||||||
 | 
						.long	0		/* 0x234 */
 | 
				
			||||||
 | 
						.long	0		/* 0x238 */
 | 
				
			||||||
 | 
						.long	0		/* 0x23c */
 | 
				
			||||||
 | 
						.long	0		/* 0x240 */
 | 
				
			||||||
 | 
						.long	0		/* 0x244 */
 | 
				
			||||||
 | 
						.long	0		/* 0x248 */
 | 
				
			||||||
 | 
						.long	0		/* 0x24c */
 | 
				
			||||||
 | 
						.long	0		/* 0x250 */
 | 
				
			||||||
 | 
						.long	0		/* 0x254 */
 | 
				
			||||||
 | 
						.long	0		/* 0x258 */
 | 
				
			||||||
 | 
						.long	0		/* 0x25c */
 | 
				
			||||||
 | 
						.long	0		/* 0x260 */
 | 
				
			||||||
 | 
						.long	0		/* 0x264 */
 | 
				
			||||||
 | 
						.long	0		/* 0x268 */
 | 
				
			||||||
 | 
						.long	0		/* 0x26c */
 | 
				
			||||||
 | 
						.long	0		/* 0x270 */
 | 
				
			||||||
 | 
						.long	0		/* 0x274 */
 | 
				
			||||||
 | 
						.long	0		/* 0x278 */
 | 
				
			||||||
 | 
						.long	0		/* 0x27c */
 | 
				
			||||||
 | 
						.long	0		/* 0x280 */
 | 
				
			||||||
 | 
						.long	0		/* 0x284 */
 | 
				
			||||||
 | 
						.long	0		/* 0x288 */
 | 
				
			||||||
 | 
						.long	0		/* 0x28c */
 | 
				
			||||||
 | 
						.long	0		/* 0x290 */
 | 
				
			||||||
 | 
						.long	0		/* 0x294 */
 | 
				
			||||||
 | 
						.long	0		/* 0x298 */
 | 
				
			||||||
 | 
						.long	0		/* 0x29c */
 | 
				
			||||||
 | 
						.long	0		/* 0x2a0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2a4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2a8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2ac */
 | 
				
			||||||
 | 
						.long	0		/* 0x2b0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2b4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2b8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2bc */
 | 
				
			||||||
 | 
						.long	0		/* 0x2c0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2c4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2c8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2cc */
 | 
				
			||||||
 | 
						.long	0		/* 0x2d0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2d4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2d8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2dc */
 | 
				
			||||||
 | 
						.long	0		/* 0x2e0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2e4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2e8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2ec */
 | 
				
			||||||
 | 
						.long	0		/* 0x2f0 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2f4 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2f8 */
 | 
				
			||||||
 | 
						.long	0		/* 0x2fc */
 | 
				
			||||||
 | 
						.long	DOTSYM(kvmppc_h_random) - hcall_real_table
 | 
				
			||||||
	.globl	hcall_real_table_end
 | 
						.globl	hcall_real_table_end
 | 
				
			||||||
hcall_real_table_end:
 | 
					hcall_real_table_end:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -529,6 +529,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 | 
				
			||||||
	case KVM_CAP_PPC_RMA:
 | 
						case KVM_CAP_PPC_RMA:
 | 
				
			||||||
		r = 0;
 | 
							r = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case KVM_CAP_PPC_HWRNG:
 | 
				
			||||||
 | 
							r = kvmppc_hwrng_present();
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	case KVM_CAP_SYNC_MMU:
 | 
						case KVM_CAP_SYNC_MMU:
 | 
				
			||||||
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 | 
					#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,12 +24,22 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct powernv_rng {
 | 
					struct powernv_rng {
 | 
				
			||||||
	void __iomem *regs;
 | 
						void __iomem *regs;
 | 
				
			||||||
 | 
						void __iomem *regs_real;
 | 
				
			||||||
	unsigned long mask;
 | 
						unsigned long mask;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng);
 | 
					static DEFINE_PER_CPU(struct powernv_rng *, powernv_rng);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int powernv_hwrng_present(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct powernv_rng *rng;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rng = get_cpu_var(powernv_rng);
 | 
				
			||||||
 | 
						put_cpu_var(rng);
 | 
				
			||||||
 | 
						return rng != NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val)
 | 
					static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long parity;
 | 
						unsigned long parity;
 | 
				
			||||||
| 
						 | 
					@ -46,6 +56,17 @@ static unsigned long rng_whiten(struct powernv_rng *rng, unsigned long val)
 | 
				
			||||||
	return val;
 | 
						return val;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int powernv_get_random_real_mode(unsigned long *v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct powernv_rng *rng;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rng = raw_cpu_read(powernv_rng);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*v = rng_whiten(rng, in_rm64(rng->regs_real));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int powernv_get_random_long(unsigned long *v)
 | 
					int powernv_get_random_long(unsigned long *v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct powernv_rng *rng;
 | 
						struct powernv_rng *rng;
 | 
				
			||||||
| 
						 | 
					@ -80,12 +101,20 @@ static __init void rng_init_per_cpu(struct powernv_rng *rng,
 | 
				
			||||||
static __init int rng_create(struct device_node *dn)
 | 
					static __init int rng_create(struct device_node *dn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct powernv_rng *rng;
 | 
						struct powernv_rng *rng;
 | 
				
			||||||
 | 
						struct resource res;
 | 
				
			||||||
	unsigned long val;
 | 
						unsigned long val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rng = kzalloc(sizeof(*rng), GFP_KERNEL);
 | 
						rng = kzalloc(sizeof(*rng), GFP_KERNEL);
 | 
				
			||||||
	if (!rng)
 | 
						if (!rng)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (of_address_to_resource(dn, 0, &res)) {
 | 
				
			||||||
 | 
							kfree(rng);
 | 
				
			||||||
 | 
							return -ENXIO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rng->regs_real = (void __iomem *)res.start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rng->regs = of_iomap(dn, 0);
 | 
						rng->regs = of_iomap(dn, 0);
 | 
				
			||||||
	if (!rng->regs) {
 | 
						if (!rng->regs) {
 | 
				
			||||||
		kfree(rng);
 | 
							kfree(rng);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -813,6 +813,7 @@ struct kvm_ppc_smmu_info {
 | 
				
			||||||
#define KVM_CAP_MIPS_MSA 112
 | 
					#define KVM_CAP_MIPS_MSA 112
 | 
				
			||||||
#define KVM_CAP_S390_INJECT_IRQ 113
 | 
					#define KVM_CAP_S390_INJECT_IRQ 113
 | 
				
			||||||
#define KVM_CAP_S390_IRQ_STATE 114
 | 
					#define KVM_CAP_S390_IRQ_STATE 114
 | 
				
			||||||
 | 
					#define KVM_CAP_PPC_HWRNG 115
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef KVM_CAP_IRQ_ROUTING
 | 
					#ifdef KVM_CAP_IRQ_ROUTING
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue