github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/bcm2835/rng.go (about) 1 // BCM2835 SoC Random Number Generator (RNG) driver 2 // https://github.com/f-secure-foundry/tamago 3 // 4 // Copyright (c) the bcm2835 package authors 5 // 6 // Use of this source code is governed by the license 7 // that can be found in the LICENSE file. 8 9 package bcm2835 10 11 import ( 12 "sync" 13 _ "unsafe" 14 15 "github.com/f-secure-foundry/tamago/internal/reg" 16 ) 17 18 // RNG registers 19 const ( 20 RNG_BASE = 0x104000 21 22 RNG_CTRL = RNG_BASE + 0x0 23 CTRL_EN = 1 24 25 RNG_STATUS = RNG_BASE + 0x4 26 RNG_DATA = RNG_BASE + 0x8 27 ) 28 29 const warmupCount = 0x40000 30 31 // Rng represents a Random number generator instance 32 type Rng struct { 33 sync.Mutex 34 35 status uint32 36 data uint32 37 ctrl uint32 38 } 39 40 // RNG (Random Number Generator) instance 41 var RNG = &Rng{} 42 43 //go:linkname initRNG runtime.initRNG 44 func initRNG() { 45 RNG.Init() 46 } 47 48 //go:linkname getRandomData runtime.getRandomData 49 func getRandomData(b []byte) { 50 RNG.getRandomData(b) 51 } 52 53 // Init initializes the RNG by discarding 'warmup bytes'. 54 func (hw *Rng) Init() { 55 hw.Lock() 56 defer hw.Unlock() 57 58 hw.status = PeripheralAddress(RNG_STATUS) 59 hw.data = PeripheralAddress(RNG_DATA) 60 hw.ctrl = PeripheralAddress(RNG_CTRL) 61 62 // Discard 63 reg.Write(hw.status, warmupCount) 64 reg.Write(hw.ctrl, CTRL_EN) 65 } 66 67 func (hw *Rng) getRandomData(b []byte) { 68 hw.Lock() 69 defer hw.Unlock() 70 71 read := 0 72 need := len(b) 73 74 for read < need { 75 // Wait for at least one word to be available 76 for (reg.Read(hw.status) >> 24) == 0 { 77 } 78 79 read = fill(b, read, reg.Read(hw.data)) 80 } 81 } 82 83 func fill(b []byte, index int, val uint32) int { 84 shift := 0 85 limit := len(b) 86 87 for (index < limit) && (shift <= 24) { 88 b[index] = byte((val >> shift) & 0xff) 89 index++ 90 shift += 8 91 } 92 93 return index 94 }