1128059Smarkm/*- 2256381Smarkm * Copyright (c) 2013 Mark R V Murray 3128059Smarkm * All rights reserved. 4128059Smarkm * 5128059Smarkm * Redistribution and use in source and binary forms, with or without 6128059Smarkm * modification, are permitted provided that the following conditions 7128059Smarkm * are met: 8128059Smarkm * 1. Redistributions of source code must retain the above copyright 9128059Smarkm * notice, this list of conditions and the following disclaimer 10128059Smarkm * in this position and unchanged. 11128059Smarkm * 2. Redistributions in binary form must reproduce the above copyright 12128059Smarkm * notice, this list of conditions and the following disclaimer in the 13128059Smarkm * documentation and/or other materials provided with the distribution. 14128059Smarkm * 15128059Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16128059Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17128059Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18128059Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19128059Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20128059Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21128059Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22128059Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23128059Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24128059Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25128059Smarkm * 26128059Smarkm */ 27128059Smarkm 28128059Smarkm#include <sys/cdefs.h> 29128059Smarkm__FBSDID("$FreeBSD$"); 30128059Smarkm 31128368Smarkm#include <sys/param.h> 32256381Smarkm#include <sys/kernel.h> 33128059Smarkm#include <sys/lock.h> 34256381Smarkm#include <sys/malloc.h> 35254147Sobrien#include <sys/module.h> 36256381Smarkm#include <sys/random.h> 37128059Smarkm#include <sys/selinfo.h> 38128368Smarkm#include <sys/systm.h> 39128059Smarkm 40256381Smarkm#include <machine/segments.h> 41208834Skib#include <machine/pcb.h> 42254147Sobrien#include <machine/md_var.h> 43254147Sobrien#include <machine/specialreg.h> 44208834Skib 45256381Smarkm#include <dev/random/randomdev.h> 46256381Smarkm#include <dev/random/randomdev_soft.h> 47256381Smarkm#include <dev/random/random_harvestq.h> 48256381Smarkm#include <dev/random/live_entropy_sources.h> 49254147Sobrien#include <dev/random/random_adaptors.h> 50128059Smarkm 51128368Smarkmstatic void random_nehemiah_init(void); 52153575Spsstatic void random_nehemiah_deinit(void); 53128059Smarkmstatic int random_nehemiah_read(void *, int); 54128059Smarkm 55256381Smarkmstatic struct random_hardware_source random_nehemiah = { 56256381Smarkm .ident = "Hardware, VIA Nehemiah Padlock RNG", 57256381Smarkm .source = RANDOM_PURE_NEHEMIAH, 58256381Smarkm .read = random_nehemiah_read 59128059Smarkm}; 60128059Smarkm 61256381Smarkm/* TODO: now that the Davies-Meyer hash is gone and we only use 62256381Smarkm * the 'xstore' instruction, do we still need to preserve the 63256381Smarkm * FPU state with fpu_kern_(enter|leave)() ? 64128368Smarkm */ 65230426Skibstatic struct fpu_kern_ctx *fpu_ctx_save; 66208834Skib 67256381Smarkm/* This H/W source never stores more than 8 bytes in one go */ 68128059Smarkm/* ARGSUSED */ 69128368Smarkmstatic __inline size_t 70128368SmarkmVIA_RNG_store(void *buf) 71128368Smarkm{ 72128368Smarkm uint32_t retval = 0; 73128368Smarkm uint32_t rate = 0; 74128368Smarkm 75256381Smarkm#ifdef __GNUCLIKE_ASM 76128368Smarkm __asm __volatile( 77256381Smarkm "movl $0,%%edx\n\t" 78256381Smarkm ".byte 0x0f, 0xa7, 0xc0" /* xstore */ 79128368Smarkm : "=a" (retval), "+d" (rate), "+D" (buf) 80128368Smarkm : 81128368Smarkm : "memory" 82128368Smarkm ); 83256381Smarkm#endif 84128368Smarkm if (rate == 0) 85128368Smarkm return (retval&0x1f); 86128368Smarkm return (0); 87128368Smarkm} 88128368Smarkm 89128368Smarkmstatic void 90128368Smarkmrandom_nehemiah_init(void) 91128368Smarkm{ 92192774Smarkm 93230426Skib fpu_ctx_save = fpu_kern_alloc_ctx(FPU_KERN_NORMAL); 94128368Smarkm} 95128368Smarkm 96256381Smarkmstatic void 97153575Spsrandom_nehemiah_deinit(void) 98153575Sps{ 99230426Skib 100230426Skib fpu_kern_free_ctx(fpu_ctx_save); 101153575Sps} 102153575Sps 103128059Smarkmstatic int 104128059Smarkmrandom_nehemiah_read(void *buf, int c) 105128059Smarkm{ 106256381Smarkm uint8_t *b; 107128368Smarkm size_t count, ret; 108256381Smarkm uint64_t tmp; 109128059Smarkm 110256381Smarkm if ((fpu_kern_enter(curthread, fpu_ctx_save, FPU_KERN_NORMAL) == 0)) { 111256381Smarkm b = buf; 112256381Smarkm for (count = c; count > 0; count -= ret) { 113256381Smarkm ret = MIN(VIA_RNG_store(&tmp), count); 114256381Smarkm memcpy(b, &tmp, ret); 115256381Smarkm b += ret; 116256381Smarkm } 117256381Smarkm fpu_kern_leave(curthread, fpu_ctx_save); 118208834Skib } 119256381Smarkm else 120256381Smarkm c = 0; 121153575Sps 122128059Smarkm return (c); 123128059Smarkm} 124240135Skib 125254147Sobrienstatic int 126254147Sobriennehemiah_modevent(module_t mod, int type, void *unused) 127254147Sobrien{ 128256381Smarkm int error = 0; 129254147Sobrien 130254147Sobrien switch (type) { 131254147Sobrien case MOD_LOAD: 132254147Sobrien if (via_feature_rng & VIA_HAS_RNG) { 133256381Smarkm live_entropy_source_register(&random_nehemiah); 134256381Smarkm random_nehemiah_init(); 135256381Smarkm } else 136254147Sobrien#ifndef KLD_MODULE 137254147Sobrien if (bootverbose) 138240135Skib#endif 139256381Smarkm printf("%s: VIA Padlock RNG not present\n", 140254147Sobrien random_nehemiah.ident); 141256381Smarkm break; 142256381Smarkm 143256381Smarkm case MOD_UNLOAD: 144256381Smarkm if (via_feature_rng & VIA_HAS_RNG) 145256381Smarkm random_nehemiah_deinit(); 146256381Smarkm live_entropy_source_deregister(&random_nehemiah); 147256381Smarkm break; 148256381Smarkm 149256381Smarkm case MOD_SHUTDOWN: 150256381Smarkm break; 151256381Smarkm 152256381Smarkm default: 153256381Smarkm error = EOPNOTSUPP; 154256381Smarkm break; 155256381Smarkm 156254147Sobrien } 157254147Sobrien 158256381Smarkm return (error); 159254147Sobrien} 160254147Sobrien 161256381SmarkmLIVE_ENTROPY_SRC_MODULE(nehemiah, nehemiah_modevent, 1); 162