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

     1  // RISC-V processor support
     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 riscv
    11  
    12  import (
    13  	"errors"
    14  	"sync"
    15  
    16  	"github.com/usbarmory/tamago/bits"
    17  )
    18  
    19  // PMP CSRs constants
    20  // (3.7.1 Physical Memory Protection CSRs
    21  // RISC-V Privileged Architectures V20211203).
    22  const (
    23  	PMP_CFG_L = 7 // lock
    24  	PMP_CFG_A = 3 // address-matching mode
    25  	PMP_CFG_X = 2 // execution access
    26  	PMP_CFG_W = 1 // write access
    27  	PMP_CFG_R = 0 // read access
    28  
    29  	PMP_A_OFF   = 0 // Null region (disabled)
    30  	PMP_A_TOR   = 1 // Top of range
    31  	PMP_A_NA4   = 2 // Naturally aligned four-byte region
    32  	PMP_A_NAPOT = 3 // Naturally aligned power-of-two region, ≥8 bytes
    33  )
    34  
    35  // PMP CSRs helpers for RV64, only 8 PMPs are supported for now. In the future,
    36  // to support up to 64 PMPs, this will benefit from dynamic generation with
    37  // go:generate.
    38  
    39  // defined in pmp.s
    40  func read_pmpcfg0() uint64
    41  func read_pmpaddr0() uint64
    42  func read_pmpaddr1() uint64
    43  func read_pmpaddr2() uint64
    44  func read_pmpaddr3() uint64
    45  func read_pmpaddr4() uint64
    46  func read_pmpaddr5() uint64
    47  func read_pmpaddr6() uint64
    48  func read_pmpaddr7() uint64
    49  func write_pmpcfg0(uint64)
    50  func write_pmpaddr0(uint64)
    51  func write_pmpaddr1(uint64)
    52  func write_pmpaddr2(uint64)
    53  func write_pmpaddr3(uint64)
    54  func write_pmpaddr4(uint64)
    55  func write_pmpaddr5(uint64)
    56  func write_pmpaddr6(uint64)
    57  func write_pmpaddr7(uint64)
    58  
    59  var mux sync.Mutex
    60  
    61  // ReadPMP returns the Physical Memory Protection CSRs, configuration and
    62  // address, for the relevant index (currently limited to PMPs from 0 to 7).
    63  func (cpu *CPU) ReadPMP(i int) (addr uint64, r bool, w bool, x bool, a int, l bool, err error) {
    64  	mux.Lock()
    65  	defer mux.Unlock()
    66  
    67  	switch i {
    68  	case 0:
    69  		addr = read_pmpaddr0()
    70  	case 1:
    71  		addr = read_pmpaddr1()
    72  	case 2:
    73  		addr = read_pmpaddr2()
    74  	case 3:
    75  		addr = read_pmpaddr3()
    76  	case 4:
    77  		addr = read_pmpaddr4()
    78  	case 5:
    79  		addr = read_pmpaddr5()
    80  	case 6:
    81  		addr = read_pmpaddr6()
    82  	case 7:
    83  		addr = read_pmpaddr7()
    84  	default:
    85  		err = errors.New("unsupported PMP index")
    86  		return
    87  	}
    88  
    89  	// addr holds bits 55:2
    90  	addr = addr << 2
    91  
    92  	cfg := read_pmpcfg0()
    93  	off := i * 8
    94  
    95  	r = bits.Get64(&cfg, off+PMP_CFG_R, 1) == 1
    96  	w = bits.Get64(&cfg, off+PMP_CFG_W, 1) == 1
    97  	x = bits.Get64(&cfg, off+PMP_CFG_X, 1) == 1
    98  	l = bits.Get64(&cfg, off+PMP_CFG_L, 1) == 1
    99  	a = int(bits.Get64(&cfg, off+PMP_CFG_A, 0b11))
   100  
   101  	return
   102  }
   103  
   104  // WritePMP sets the Physical Memory Protection CSRs, configuration and
   105  // address, for the relevant index (currently limited to PMPs from 0 to 7).
   106  func (cpu *CPU) WritePMP(i int, addr uint64, r bool, w bool, x bool, a int, l bool) (err error) {
   107  	mux.Lock()
   108  	defer mux.Unlock()
   109  
   110  	// addr holds bits 55:2
   111  	addr = addr >> 2
   112  
   113  	switch i {
   114  	case 0:
   115  		write_pmpaddr0(addr)
   116  	case 1:
   117  		write_pmpaddr1(addr)
   118  	case 2:
   119  		write_pmpaddr2(addr)
   120  	case 3:
   121  		write_pmpaddr3(addr)
   122  	case 4:
   123  		write_pmpaddr4(addr)
   124  	case 5:
   125  		write_pmpaddr5(addr)
   126  	case 6:
   127  		write_pmpaddr6(addr)
   128  	case 7:
   129  		write_pmpaddr7(addr)
   130  	default:
   131  		err = errors.New("unsupported PMP index")
   132  		return
   133  	}
   134  
   135  	cfg := read_pmpcfg0()
   136  	off := i * 8
   137  
   138  	bits.SetTo64(&cfg, off+PMP_CFG_R, r)
   139  	bits.SetTo64(&cfg, off+PMP_CFG_W, w)
   140  	bits.SetTo64(&cfg, off+PMP_CFG_X, x)
   141  	bits.SetTo64(&cfg, off+PMP_CFG_L, l)
   142  	bits.SetN64(&cfg, off+PMP_CFG_A, 0b11, uint64(a))
   143  
   144  	write_pmpcfg0(cfg)
   145  
   146  	return
   147  }