1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/riscv_common/periph/pmp.c
2023-06-28 11:55:34 +02:00

301 lines
10 KiB
C

/*
* Copyright (C) 2023 Bennet Blischke <bennet.blischke@haw-hamburg.de>
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup cpu_riscv_common
* @{
*
* @file
* @brief RISCV PMP implementation
*
* @author Bennet Blischke
*/
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include "cpu_conf.h"
#include "vendor/riscv_csr.h"
#include "pmp.h"
#if NUM_PMP_ENTRIES != 16 && NUM_PMP_ENTRIES != 64
#error "Only 16 or 64 PMP entries allowed."
#endif
#define _WRITE_PMPCFG(REG, VALUE) write_csr(REG, VALUE)
#define _READ_PMPCFG(REG) read_csr(REG)
#define WRITE_PMPCFG(REG, VALUE) _WRITE_PMPCFG(CSR_PMPCFG0 + REG, VALUE)
#define READ_PMPCFG(REG) _READ_PMPCFG(CSR_PMPCFG0 + REG)
/* These shifts are needed as the PMP Address registers stores
* 34 Bit addresses with 4 byte alignment in a 32 bit register
*/
#define _WRITE_PMPADDR(REG, VALUE) write_csr(REG, VALUE >> 2)
#define _READ_PMPADDR(REG) (read_csr(REG) << 2)
#define WRITE_PMPADDR(REG, VALUE) _WRITE_PMPADDR(CSR_PMPADDR0 + REG, VALUE)
#define READ_PMPADDR(REG) _READ_PMPADDR(CSR_PMPADDR0 + REG)
#define _NAPOT_base(addr) (addr & (addr + 1))
#define _NAPOT_end(addr) (addr | (addr + 1))
/* The assembly instructions for reading riscv CSRs, encode the CSR-address
* in the immediate field which is not changeable at run-time.
* Hence it is needed to generate all possible register accesses at build-time.
* Settled for switch-case as they are easiest to read, understand and maintain.
*/
void write_pmpcfg(uint8_t reg_num, uint32_t value)
{
assert(reg_num < NUM_PMP_ENTRIES / 4);
switch (reg_num) {
case 0: WRITE_PMPCFG(0, value); break;
case 1: WRITE_PMPCFG(1, value); break;
case 2: WRITE_PMPCFG(2, value); break;
case 3: WRITE_PMPCFG(3, value); break;
#if NUM_PMP_ENTRIES == 64
case 4: WRITE_PMPCFG(4, value); break;
case 5: WRITE_PMPCFG(5, value); break;
case 6: WRITE_PMPCFG(6, value); break;
case 7: WRITE_PMPCFG(7, value); break;
case 8: WRITE_PMPCFG(8, value); break;
case 9: WRITE_PMPCFG(9, value); break;
case 10: WRITE_PMPCFG(10, value); break;
case 11: WRITE_PMPCFG(11, value); break;
case 12: WRITE_PMPCFG(12, value); break;
case 13: WRITE_PMPCFG(13, value); break;
case 14: WRITE_PMPCFG(14, value); break;
case 15: WRITE_PMPCFG(15, value); break;
#endif
}
}
uint32_t read_pmpcfg(uint8_t reg_num)
{
assert(reg_num < NUM_PMP_ENTRIES / 4);
switch (reg_num) {
case 0: return READ_PMPCFG(0);
case 1: return READ_PMPCFG(1);
case 2: return READ_PMPCFG(2);
case 3: return READ_PMPCFG(3);
#if NUM_PMP_ENTRIES == 64
case 4: return READ_PMPCFG(4);
case 5: return READ_PMPCFG(5);
case 6: return READ_PMPCFG(6);
case 7: return READ_PMPCFG(7);
case 8: return READ_PMPCFG(8);
case 9: return READ_PMPCFG(9);
case 10: return READ_PMPCFG(10);
case 11: return READ_PMPCFG(11);
case 12: return READ_PMPCFG(12);
case 13: return READ_PMPCFG(13);
case 14: return READ_PMPCFG(14);
case 15: return READ_PMPCFG(15);
#endif
}
return 0;
}
void write_pmpaddr(uint8_t reg_num, uint32_t value)
{
assert(reg_num < NUM_PMP_ENTRIES);
switch (reg_num) {
case 0: WRITE_PMPADDR(0, value); break;
case 1: WRITE_PMPADDR(1, value); break;
case 2: WRITE_PMPADDR(2, value); break;
case 3: WRITE_PMPADDR(3, value); break;
case 4: WRITE_PMPADDR(4, value); break;
case 5: WRITE_PMPADDR(5, value); break;
case 6: WRITE_PMPADDR(6, value); break;
case 7: WRITE_PMPADDR(7, value); break;
case 8: WRITE_PMPADDR(8, value); break;
case 9: WRITE_PMPADDR(9, value); break;
case 10: WRITE_PMPADDR(10, value); break;
case 11: WRITE_PMPADDR(11, value); break;
case 12: WRITE_PMPADDR(12, value); break;
case 13: WRITE_PMPADDR(13, value); break;
case 14: WRITE_PMPADDR(14, value); break;
case 15: WRITE_PMPADDR(15, value); break;
#if NUM_PMP_ENTRIES == 64
case 16: WRITE_PMPADDR(16, value); break;
case 17: WRITE_PMPADDR(17, value); break;
case 18: WRITE_PMPADDR(18, value); break;
case 19: WRITE_PMPADDR(19, value); break;
case 20: WRITE_PMPADDR(20, value); break;
case 21: WRITE_PMPADDR(21, value); break;
case 22: WRITE_PMPADDR(22, value); break;
case 23: WRITE_PMPADDR(23, value); break;
case 24: WRITE_PMPADDR(24, value); break;
case 25: WRITE_PMPADDR(25, value); break;
case 26: WRITE_PMPADDR(26, value); break;
case 27: WRITE_PMPADDR(27, value); break;
case 28: WRITE_PMPADDR(28, value); break;
case 29: WRITE_PMPADDR(29, value); break;
case 30: WRITE_PMPADDR(30, value); break;
case 31: WRITE_PMPADDR(31, value); break;
case 32: WRITE_PMPADDR(32, value); break;
case 33: WRITE_PMPADDR(33, value); break;
case 34: WRITE_PMPADDR(34, value); break;
case 35: WRITE_PMPADDR(35, value); break;
case 36: WRITE_PMPADDR(36, value); break;
case 37: WRITE_PMPADDR(37, value); break;
case 38: WRITE_PMPADDR(38, value); break;
case 39: WRITE_PMPADDR(39, value); break;
case 40: WRITE_PMPADDR(40, value); break;
case 41: WRITE_PMPADDR(41, value); break;
case 42: WRITE_PMPADDR(42, value); break;
case 43: WRITE_PMPADDR(43, value); break;
case 44: WRITE_PMPADDR(44, value); break;
case 45: WRITE_PMPADDR(45, value); break;
case 46: WRITE_PMPADDR(46, value); break;
case 47: WRITE_PMPADDR(47, value); break;
case 48: WRITE_PMPADDR(48, value); break;
case 49: WRITE_PMPADDR(49, value); break;
case 50: WRITE_PMPADDR(50, value); break;
case 51: WRITE_PMPADDR(51, value); break;
case 52: WRITE_PMPADDR(52, value); break;
case 53: WRITE_PMPADDR(53, value); break;
case 54: WRITE_PMPADDR(54, value); break;
case 55: WRITE_PMPADDR(55, value); break;
case 56: WRITE_PMPADDR(56, value); break;
case 57: WRITE_PMPADDR(57, value); break;
case 58: WRITE_PMPADDR(58, value); break;
case 59: WRITE_PMPADDR(59, value); break;
case 60: WRITE_PMPADDR(60, value); break;
case 61: WRITE_PMPADDR(61, value); break;
case 62: WRITE_PMPADDR(62, value); break;
case 63: WRITE_PMPADDR(63, value); break;
#endif
}
}
uint32_t read_pmpaddr(uint8_t reg_num)
{
assert(reg_num < NUM_PMP_ENTRIES);
switch (reg_num) {
case 0: return READ_PMPADDR(0);
case 1: return READ_PMPADDR(1);
case 2: return READ_PMPADDR(2);
case 3: return READ_PMPADDR(3);
case 4: return READ_PMPADDR(4);
case 5: return READ_PMPADDR(5);
case 6: return READ_PMPADDR(6);
case 7: return READ_PMPADDR(7);
case 8: return READ_PMPADDR(8);
case 9: return READ_PMPADDR(9);
case 10: return READ_PMPADDR(10);
case 11: return READ_PMPADDR(11);
case 12: return READ_PMPADDR(12);
case 13: return READ_PMPADDR(13);
case 14: return READ_PMPADDR(14);
case 15: return READ_PMPADDR(15);
#if NUM_PMP_ENTRIES == 64
case 16: return READ_PMPADDR(16);
case 17: return READ_PMPADDR(17);
case 18: return READ_PMPADDR(18);
case 19: return READ_PMPADDR(19);
case 20: return READ_PMPADDR(20);
case 21: return READ_PMPADDR(21);
case 22: return READ_PMPADDR(22);
case 23: return READ_PMPADDR(23);
case 24: return READ_PMPADDR(24);
case 25: return READ_PMPADDR(25);
case 26: return READ_PMPADDR(26);
case 27: return READ_PMPADDR(27);
case 28: return READ_PMPADDR(28);
case 29: return READ_PMPADDR(29);
case 30: return READ_PMPADDR(30);
case 31: return READ_PMPADDR(31);
case 32: return READ_PMPADDR(32);
case 33: return READ_PMPADDR(33);
case 34: return READ_PMPADDR(34);
case 35: return READ_PMPADDR(35);
case 36: return READ_PMPADDR(36);
case 37: return READ_PMPADDR(37);
case 38: return READ_PMPADDR(38);
case 39: return READ_PMPADDR(39);
case 40: return READ_PMPADDR(40);
case 41: return READ_PMPADDR(41);
case 42: return READ_PMPADDR(42);
case 43: return READ_PMPADDR(43);
case 44: return READ_PMPADDR(44);
case 45: return READ_PMPADDR(45);
case 46: return READ_PMPADDR(46);
case 47: return READ_PMPADDR(47);
case 48: return READ_PMPADDR(48);
case 49: return READ_PMPADDR(49);
case 50: return READ_PMPADDR(50);
case 51: return READ_PMPADDR(51);
case 52: return READ_PMPADDR(52);
case 53: return READ_PMPADDR(53);
case 54: return READ_PMPADDR(54);
case 55: return READ_PMPADDR(55);
case 56: return READ_PMPADDR(56);
case 57: return READ_PMPADDR(57);
case 58: return READ_PMPADDR(58);
case 59: return READ_PMPADDR(59);
case 60: return READ_PMPADDR(60);
case 61: return READ_PMPADDR(61);
case 62: return READ_PMPADDR(62);
case 63: return READ_PMPADDR(63);
#endif
}
return 0;
}
uint8_t get_pmpcfg(uint8_t entry)
{
return (read_pmpcfg(entry / 4) >> (entry % 4) * 8) & 0xFF;
}
void set_pmpcfg(uint8_t entry, uint8_t value)
{
uint32_t cur_value = read_pmpcfg(entry / 4);
uint32_t mask = 0xff << (entry % 4) * 8;
cur_value &= ~mask;
cur_value |= value << (entry % 4) * 8;
write_pmpcfg(entry / 4, cur_value);
}
void print_pmpcfg(uint8_t entry)
{
uint8_t cfg = get_pmpcfg(entry);
uint32_t start = 0;
uint32_t stop = 0;
char *mode = "OFF ";
switch (cfg & PMP_A) {
case PMP_TOR:
mode = "TOR ";
start = (entry > 0) ? read_pmpaddr(entry - 1) : 0;
stop = read_pmpaddr(entry);
break;
case PMP_NA4:
mode = "NA4 ";
start = read_pmpaddr(entry);
stop = start + 3;
break;
case PMP_NAPOT:
mode = "NAPOT";
/* Flipp last two bits in NAPOT mode */
uint32_t _tmp = read_pmpaddr(entry) | 0x03;
start = _NAPOT_base(_tmp);
stop = _NAPOT_end(_tmp);
break;
}
printf("pmp%02dcfg: %c %c%c%c %s 0x%08x - 0x%08x\n",
entry,
(cfg & PMP_L) ? 'L' : '-',
(cfg & PMP_R) ? 'R' : '-',
(cfg & PMP_W) ? 'W' : '-',
(cfg & PMP_X) ? 'X' : '-',
mode,
(unsigned int)start,
(unsigned int)stop
);
}