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 }