github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/bcm2835/rng.go (about)

     1  // BCM2835 SoC Random Number Generator (RNG) driver
     2  // https://github.com/usbarmory/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/usbarmory/tamago/internal/reg"
    16  	"github.com/usbarmory/tamago/internal/rng"
    17  )
    18  
    19  // RNG registers
    20  const (
    21  	RNG_BASE = 0x104000
    22  
    23  	RNG_CTRL = RNG_BASE + 0x0
    24  	CTRL_EN  = 1
    25  
    26  	RNG_STATUS = RNG_BASE + 0x4
    27  	RNG_DATA   = RNG_BASE + 0x8
    28  )
    29  
    30  const warmupCount = 0x40000
    31  
    32  // Rng represents a Random number generator instance
    33  type Rng struct {
    34  	sync.Mutex
    35  
    36  	status uint32
    37  	data   uint32
    38  	ctrl   uint32
    39  }
    40  
    41  //go:linkname initRNG runtime.initRNG
    42  func initRNG() {
    43  	r := &Rng{}
    44  	r.Init()
    45  
    46  	rng.GetRandomDataFn = r.getRandomData
    47  }
    48  
    49  // Init initializes the RNG by discarding 'warmup bytes'.
    50  func (hw *Rng) Init() {
    51  	hw.Lock()
    52  	defer hw.Unlock()
    53  
    54  	hw.status = PeripheralAddress(RNG_STATUS)
    55  	hw.data = PeripheralAddress(RNG_DATA)
    56  	hw.ctrl = PeripheralAddress(RNG_CTRL)
    57  
    58  	// Discard
    59  	reg.Write(hw.status, warmupCount)
    60  	reg.Write(hw.ctrl, CTRL_EN)
    61  }
    62  
    63  func (hw *Rng) getRandomData(b []byte) {
    64  	hw.Lock()
    65  	defer hw.Unlock()
    66  
    67  	read := 0
    68  	need := len(b)
    69  
    70  	for read < need {
    71  		// Wait for at least one word to be available
    72  		for (reg.Read(hw.status) >> 24) == 0 {
    73  		}
    74  
    75  		read = rng.Fill(b, read, reg.Read(hw.data))
    76  	}
    77  }