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  }