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

     1  // First-fit memory allocator for DMA buffers
     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 dma provides primitives for direct memory allocation and alignment,
    11  // it is primarily used in bare metal device driver operation to avoid passing
    12  // Go pointers for DMA purposes.
    13  //
    14  // This package is only meant to be used with `GOOS=tamago` as supported by the
    15  // TamaGo framework for bare metal Go on ARM/RISC-V SoCs, see
    16  // https://github.com/usbarmory/tamago.
    17  package dma
    18  
    19  import (
    20  	"fmt"
    21  	"runtime"
    22  )
    23  
    24  // NewRegion initializes a memory region for DMA buffer allocation.
    25  //
    26  // To avoid unforseen consequences the caller must ensure that allocated
    27  // regions do not overlap among themselves or with the global one (see Init()).
    28  //
    29  // To allow allocation of DMA buffers within Go runtime memory the unsafe flag
    30  // must be set.
    31  func NewRegion(addr uint, size int, unsafe bool) (r *Region, err error) {
    32  	start := uint(addr)
    33  	end := uint(start) + uint(size)
    34  
    35  	// returns uint32/uint64 depending on platform
    36  	rs, re := runtime.MemRegion()
    37  	ramStart := uint(rs)
    38  	ramEnd := uint(re)
    39  
    40  	if !unsafe &&
    41  		(ramStart >= start && ramStart < end ||
    42  			ramEnd > start && ramEnd < end ||
    43  			start >= ramStart && end < ramEnd) {
    44  		return nil, fmt.Errorf("DMA within Go runtime memory (%#x-%#x) is not allowed", ramStart, ramEnd)
    45  	}
    46  
    47  	r = &Region{}
    48  	r.Init(start, uint(size))
    49  
    50  	return
    51  }
    52  
    53  // Init initializes the global memory region for DMA buffer allocation, used
    54  // throughout the tamago package for all DMA allocations.
    55  //
    56  // Additional DMA regions for application use can be allocated through
    57  // NewRegion().
    58  func Init(start uint, size int) (err error) {
    59  	dma, err = NewRegion(start, size, false)
    60  	return
    61  }
    62  
    63  // Reserve is the equivalent of Region.Reserve() on the global DMA region.
    64  func Reserve(size int, align int) (addr uint, buf []byte) {
    65  	return dma.Reserve(size, align)
    66  }
    67  
    68  // Reserved is the equivalent of Region.Reserved() on the global DMA region.
    69  func Reserved(buf []byte) (res bool, addr uint) {
    70  	return dma.Reserved(buf)
    71  }
    72  
    73  // Alloc is the equivalent of Region.Alloc() on the global DMA region.
    74  func Alloc(buf []byte, align int) (addr uint) {
    75  	return dma.Alloc(buf, align)
    76  }
    77  
    78  // Read is the equivalent of Region.Read() on the global DMA region.
    79  func Read(addr uint, off int, buf []byte) {
    80  	dma.Read(addr, off, buf)
    81  }
    82  
    83  // Write is the equivalent of Region.Write() on the global DMA region.
    84  func Write(addr uint, off int, buf []byte) {
    85  	dma.Write(addr, off, buf)
    86  }
    87  
    88  // Free is the equivalent of Region.Free() on the global DMA region.
    89  func Free(addr uint) {
    90  	dma.Free(addr)
    91  }
    92  
    93  // Release is the equivalent of Region.Release() on the global DMA region.
    94  func Release(addr uint) {
    95  	dma.Release(addr)
    96  }