github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/nxp/caam/job.go (about)

     1  // NXP Cryptographic Acceleration and Assurance Module (CAAM) driver
     2  // https://github.com/usbarmory/tamago
     3  //
     4  // Copyright (c) WithSecure Corporation
     5  // https://foundry.withsecure.com
     6  //
     7  // Use of this source code is governed by the license
     8  // that can be found in the LICENSE file.
     9  
    10  package caam
    11  
    12  import (
    13  	"fmt"
    14  	"sync"
    15  
    16  	"github.com/usbarmory/tamago/dma"
    17  	"github.com/usbarmory/tamago/internal/reg"
    18  )
    19  
    20  // CAAM Job Ring registers
    21  const (
    22  	CAAM_JR0_MIDR_MS = 0x10
    23  	CAAM_JR1_MIDR_MS = 0x18
    24  	CAAM_JR2_MIDR_MS = 0x20
    25  
    26  	JRxMIDR_MS_JROWN_NS = 3
    27  
    28  	CAAM_JRSTART = 0x5c
    29  
    30  	CAAM_JR0_BASE = 0x1000
    31  	CAAM_JR1_BASE = 0x2000
    32  	CAAM_JR2_BASE = 0x3000
    33  
    34  	CAAM_IRBAR_JRx = 0x04
    35  	CAAM_IRSR_JRx  = 0x0c
    36  	CAAM_IRJAR_JRx = 0x1c
    37  	CAAM_ORBAR_JRx = 0x24
    38  	CAAM_ORSR_JRx  = 0x2c
    39  	CAAM_ORJRR_JRx = 0x34
    40  	CAAM_ORSFR_JRx = 0x3c
    41  )
    42  
    43  const (
    44  	jobRingInterface = CAAM_JR0_BASE
    45  	jobRingSize      = 1
    46  	jobWords         = 1
    47  	jobResultWords   = 2
    48  )
    49  
    50  var once sync.Once
    51  
    52  type jobRing struct {
    53  	sync.Mutex
    54  
    55  	// base register
    56  	base uint32
    57  
    58  	// control registers
    59  	irjar uint32
    60  	orjrr uint32
    61  	orsfr uint32
    62  
    63  	// input/output ring size
    64  	size int
    65  	// job queue
    66  	input uint32
    67  	// results queue
    68  	output uint32
    69  }
    70  
    71  func (ring *jobRing) initQueue(words int, size int) uint32 {
    72  	buf := make([]byte, size*words*4)
    73  	return uint32(dma.Alloc(buf, 4))
    74  }
    75  
    76  func (ring *jobRing) init(base uint32, size int) {
    77  	ring.base = base
    78  	ring.irjar = ring.base + CAAM_IRJAR_JRx
    79  	ring.orjrr = ring.base + CAAM_ORJRR_JRx
    80  	ring.orsfr = ring.base + CAAM_ORSFR_JRx
    81  
    82  	if ring.size > 0 {
    83  		dma.Free(uint(ring.input))
    84  		dma.Free(uint(ring.output))
    85  	}
    86  
    87  	ring.size = size
    88  	ring.input = ring.initQueue(jobWords, ring.size)
    89  	ring.output = ring.initQueue(jobResultWords, ring.size)
    90  
    91  	reg.Write(ring.base+CAAM_IRBAR_JRx, ring.input)
    92  	reg.Write(ring.base+CAAM_IRSR_JRx, uint32(ring.size))
    93  
    94  	reg.Write(ring.base+CAAM_ORBAR_JRx, ring.output)
    95  	reg.Write(ring.base+CAAM_ORSFR_JRx, uint32(ring.size))
    96  }
    97  
    98  func (ring *jobRing) add(hdr *Header, jd []byte) (err error) {
    99  	if hdr == nil {
   100  		hdr = &Header{}
   101  		hdr.SetDefaults()
   102  		hdr.Length(1 + len(jd)/4)
   103  	}
   104  
   105  	jd = append(hdr.Bytes(), jd...)
   106  
   107  	ptr := dma.Alloc(jd, 4)
   108  	defer dma.Free(ptr)
   109  
   110  	ring.Lock()
   111  	defer ring.Unlock()
   112  
   113  	// add job descriptor to input ring
   114  	reg.Write(ring.input, uint32(ptr))
   115  
   116  	// signal job addition
   117  	reg.Write(ring.irjar, 1)
   118  	defer reg.Write(ring.orjrr, 1)
   119  
   120  	// wait for job completion
   121  	reg.Wait(ring.orsfr, 0, 0x3ff, 1)
   122  
   123  	if res := reg.Read(ring.output); res != uint32(ptr) {
   124  		return fmt.Errorf("CAAM job error, invalid output descriptor")
   125  	}
   126  
   127  	if status := reg.Read(ring.output + 4); status != 0 {
   128  		return fmt.Errorf("CAAM job error, status:%#x", status)
   129  	}
   130  
   131  	return
   132  }
   133  
   134  func (hw *CAAM) initJobRing() {
   135  	// start is required to enable access to job ring registers
   136  	startJRx := (jobRingInterface >> 12) - 1
   137  
   138  	jrstart := hw.Base + CAAM_JRSTART
   139  	reg.Clear(jrstart, startJRx)
   140  	reg.Set(jrstart, startJRx)
   141  
   142  	hw.jr = &jobRing{}
   143  	hw.jr.init(hw.Base+jobRingInterface, jobRingSize)
   144  
   145  	// initialize internal RNG access, required for certain CAAM commands
   146  	hw.initRNG()
   147  }
   148  
   149  func (hw *CAAM) job(hdr *Header, jd []byte) (err error) {
   150  	once.Do(hw.initJobRing)
   151  	return hw.jr.add(hdr, jd)
   152  }
   153  
   154  // SetOwner defines the bus master that is permitted to access CAAM job ring
   155  // registers. The argument defines either secure (e.g. TrustZone Secure World)
   156  // or non-secure (e.g. TrustZone Normal World) ownership.
   157  func (hw *CAAM) SetOwner(secure bool) {
   158  	reg.SetTo(hw.Base+CAAM_JR0_MIDR_MS, JRxMIDR_MS_JROWN_NS, !secure)
   159  	hw.initJobRing()
   160  }