Skip to content

Commit

Permalink
fix: correctly handle calls for GetRNG() when being made from nrf dev…
Browse files Browse the repository at this point in the history
…ices with SoftDevice enabled.

Signed-off-by: deadprogram <[email protected]>
  • Loading branch information
deadprogram committed Jan 12, 2025
1 parent 217f677 commit 5a8301f
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/machine/machine_nrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,9 @@ func (i2c *I2C) signalStop() error {

var rngStarted = false

// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
// getRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
// According to Nordic's documentation, the random output is suitable for cryptographic purposes.
func GetRNG() (ret uint32, err error) {
func getRNG() (ret uint32, err error) {
// There's no apparent way to check the status of the RNG peripheral's task, so simply start it
// to avoid deadlocking while waiting for output.
if !rngStarted {
Expand Down
9 changes: 9 additions & 0 deletions src/machine/machine_nrf_bare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build nrf && !softdevice

package machine

// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
// According to Nordic's documentation, the random output is suitable for cryptographic purposes.
func GetRNG() (ret uint32, err error) {
return getRNG()
}
56 changes: 56 additions & 0 deletions src/machine/machine_nrf_sd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//go:build nrf && softdevice

package machine

import (
"device/arm"
"device/nrf"

"errors"
)

// avoid a heap allocation in GetRNG.
var (
softdeviceEnabled uint8
bytesAvailable uint8
buf [4]uint8
)

// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
// According to Nordic's documentation, the random output is suitable for cryptographic purposes.
func GetRNG() (ret uint32, err error) {
// First check whether the SoftDevice is enabled.
// sd_rand_application_bytes_available_get cannot be called when the SoftDevice is not enabled.
arm.SVCall1(0x12, &softdeviceEnabled) // sd_softdevice_is_enabled

if softdeviceEnabled == 0 {
return getRNG()
}

// call into the SoftDevice to get random data bytes available
switch nrf.Device {
case "nrf51":
// sd_rand_application_bytes_available_get: SOC_SVC_BASE_NOT_AVAILABLE + 4
arm.SVCall1(0x2B+4, &bytesAvailable)
case "nrf52", "nrf52840", "nrf52833":
// sd_rand_application_bytes_available_get: SOC_SVC_BASE_NOT_AVAILABLE + 4
arm.SVCall1(0x2C+4, &bytesAvailable)
default:
return 0, errors.New("softdevice not supported on this device")
}

if bytesAvailable < 4 {
return 0, errors.New("not enough random data available")
}

switch nrf.Device {
case "nrf51":
// sd_rand_application_vector_get: SOC_SVC_BASE_NOT_AVAILABLE + 5
arm.SVCall2(0x2B+5, &buf, 4)
case "nrf52", "nrf52840", "nrf52833":
// sd_rand_application_vector_get: SOC_SVC_BASE_NOT_AVAILABLE + 5
arm.SVCall2(0x2C+5, &buf, 4)
}

return uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24, nil
}

0 comments on commit 5a8301f

Please sign in to comment.