5 #include "sw/device/lib/runtime/pmp.h"
18 #define PMP_CFG_CSR_R 0
19 #define PMP_CFG_CSR_W 1
20 #define PMP_CFG_CSR_X 2
21 #define PMP_CFG_CSR_A 3
22 #define PMP_CFG_CSR_L 7
24 #define PMP_CFG_FIELDS_PER_REG 4
25 #define PMP_CFG_FIELD_WIDTH 8
26 #define PMP_CFG_FIELD_MASK 0xff
30 #define PMP_CFG_CSR_MODE_OFF 0
31 #define PMP_CFG_CSR_MODE_TOR 1
32 #define PMP_CFG_CSR_MODE_NA4 2
33 #define PMP_CFG_CSR_MODE_NAPOT 3
34 #define PMP_CFG_CSR_MODE_MASK 0x3
36 typedef enum pmp_csr_access_type {
37 kPmpCsrAccessTypeRead = 0,
38 kPmpCsrAccessTypeWrite,
39 } pmp_csr_access_type_t;
42 .
mask = PMP_CFG_CSR_MODE_MASK,
43 .index = PMP_CFG_CSR_A,
58 #define PMP_REGIONS(X) \
91 static bool pmp_cfg_csr_read(pmp_region_index_t region, uint32_t *value) {
92 #define PMP_READ_CONFIG_(region_id, config_reg_id) \
94 CSR_READ(CSR_REG_PMPCFG##config_reg_id, value); \
99 PMP_REGIONS(PMP_READ_CONFIG_)
117 static bool pmp_cfg_csr_write(pmp_region_index_t region, uint32_t value) {
118 #define PMP_WRITE_CONFIG_(region_id, config_reg_id) \
120 CSR_WRITE(CSR_REG_PMPCFG##config_reg_id, value); \
125 PMP_REGIONS(PMP_WRITE_CONFIG_)
140 static bool pmp_addr_csr_read(pmp_region_index_t region, uint32_t *value) {
141 #define PMP_READ_ADDR_(region_id, _) \
143 CSR_READ(CSR_REG_PMPADDR##region_id, value); \
148 PMP_REGIONS(PMP_READ_ADDR_)
162 static bool pmp_addr_csr_write(pmp_region_index_t region, uint32_t value) {
163 #define PMP_WRITE_ADDR_(region_id, _) \
165 CSR_WRITE(CSR_REG_PMPADDR##region_id, value); \
170 PMP_REGIONS(PMP_WRITE_ADDR_)
186 static pmp_region_configure_result_t pmp_csr_cfg_field_read(
187 pmp_region_index_t region, uint32_t *field_value) {
188 uint32_t cfg_csr_original;
189 if (!pmp_cfg_csr_read(region, &cfg_csr_original)) {
190 return kPmpRegionConfigureError;
193 size_t field_index = (region % PMP_CFG_FIELDS_PER_REG) * PMP_CFG_FIELD_WIDTH;
195 .
mask = PMP_CFG_FIELD_MASK,
196 .index = field_index,
201 return kPmpRegionConfigureOk;
214 static pmp_region_configure_result_t pmp_csr_cfg_field_write(
215 pmp_region_index_t region, uint32_t field_value) {
216 uint32_t cfg_csr_current;
217 if (!pmp_cfg_csr_read(region, &cfg_csr_current)) {
218 return kPmpRegionConfigureError;
222 size_t field_index = (region % PMP_CFG_FIELDS_PER_REG) * PMP_CFG_FIELD_WIDTH;
224 .
mask = PMP_CFG_FIELD_MASK,
225 .index = field_index,
228 uint32_t cfg_csr_new =
231 if (!pmp_cfg_csr_write(region, cfg_csr_new)) {
232 return kPmpRegionConfigureError;
235 if (!pmp_cfg_csr_read(region, &cfg_csr_current)) {
236 return kPmpRegionConfigureError;
239 if (cfg_csr_current != cfg_csr_new) {
240 return kPmpRegionConfigureWarlError;
243 return kPmpRegionConfigureOk;
264 pmp_region_configure_result_t pmp_csr_address_write(pmp_region_index_t region,
266 uint32_t address_shifted = address >> PMP_ADDRESS_SHIFT;
267 if (!pmp_addr_csr_write(region, address_shifted)) {
268 return kPmpRegionConfigureError;
271 uint32_t addr_csr_after_write;
272 if (!pmp_addr_csr_read(region, &addr_csr_after_write)) {
273 return kPmpRegionConfigureError;
276 if (address_shifted != addr_csr_after_write) {
277 return kPmpRegionConfigureWarlError;
280 return kPmpRegionConfigureOk;
291 static bool pmp_cfg_permissions_set(pmp_region_permissions_t perm,
292 uint32_t *bitfield) {
294 case kPmpRegionPermissionsNone:
297 case kPmpRegionPermissionsReadOnly:
300 case kPmpRegionPermissionsExecuteOnly:
303 case kPmpRegionPermissionsReadExecute:
307 case kPmpRegionPermissionsReadWrite:
311 case kPmpRegionPermissionsReadWriteExecute:
329 static void pmp_cfg_mode_lock_set(pmp_region_lock_t lock, uint32_t *bitfield) {
330 bool flag = (lock == kPmpRegionLockLocked) ?
true :
false;
347 static bool pmp_address_aligned(uintptr_t address) {
348 return address == (address & PMP_ADDRESS_ALIGNMENT_INVERTED_MASK);
365 static pmp_region_configure_napot_result_t pmp_napot_address_construct(
366 uintptr_t address, uint32_t size, uintptr_t *pmp_address_napot) {
369 if (size < PMP_ADDRESS_ALIGNMENT || size < PMP_ADDRESS_MIN_ALIGNMENT_NAPOT) {
370 return kPmpRegionConfigureNapotBadAddress;
374 uint32_t size_mask = size - 1;
375 if ((size & size_mask) != 0) {
376 return kPmpRegionConfigureNapotBadSize;
380 if (address != (address & (~size_mask))) {
381 return kPmpRegionConfigureNapotBadAddress;
386 *pmp_address_napot = address | (size_mask >> 1);
388 return kPmpRegionConfigureNapotOk;
391 pmp_region_configure_result_t pmp_region_configure_off(
392 pmp_region_index_t region, uintptr_t address) {
393 if (region >= PMP_REGIONS_NUM) {
394 return kPmpRegionConfigureBadRegion;
397 if (!pmp_address_aligned(address)) {
398 return kPmpRegionConfigureBadAddress;
403 pmp_region_configure_result_t result = pmp_csr_address_write(region, address);
404 if (result != kPmpRegionConfigureOk) {
409 result = pmp_csr_cfg_field_write(region, 0);
410 if (result != kPmpRegionConfigureOk) {
414 return kPmpRegionConfigureOk;
417 pmp_region_configure_na4_result_t pmp_region_configure_na4(
419 if (PMP_GRANULARITY_IBEX > 0) {
420 return kPmpRegionConfigureNa4Unavailable;
423 if (region >= PMP_REGIONS_NUM) {
424 return kPmpRegionConfigureNa4BadRegion;
427 if (!pmp_address_aligned(address)) {
428 return kPmpRegionConfigureNa4BadAddress;
431 uint32_t field_value = 0;
432 if (!pmp_cfg_permissions_set(config.
permissions, &field_value)) {
433 return kPmpRegionConfigureNa4Error;
436 pmp_cfg_mode_lock_set(config.
lock, &field_value);
439 PMP_CFG_CSR_MODE_NA4);
443 pmp_region_configure_result_t result = pmp_csr_address_write(region, address);
444 if (result != kPmpRegionConfigureOk) {
445 return (pmp_region_configure_na4_result_t)result;
448 result = pmp_csr_cfg_field_write(region, field_value);
449 if (result != kPmpRegionConfigureOk) {
450 return (pmp_region_configure_na4_result_t)result;
453 return kPmpRegionConfigureNa4Ok;
456 pmp_region_configure_napot_result_t pmp_region_configure_napot(
459 if (region >= PMP_REGIONS_NUM) {
460 return kPmpRegionConfigureNapotBadRegion;
463 uintptr_t napot_address;
464 pmp_region_configure_napot_result_t napot_result =
465 pmp_napot_address_construct(address, size, &napot_address);
466 if (napot_result != kPmpRegionConfigureNapotOk) {
470 uint32_t field_value = 0;
471 if (!pmp_cfg_permissions_set(config.
permissions, &field_value)) {
472 return kPmpRegionConfigureNapotError;
475 pmp_cfg_mode_lock_set(config.
lock, &field_value);
478 PMP_CFG_CSR_MODE_NAPOT);
482 pmp_region_configure_result_t result =
483 pmp_csr_address_write(region, napot_address);
484 if (result != kPmpRegionConfigureOk) {
485 return (pmp_region_configure_napot_result_t)result;
488 result = pmp_csr_cfg_field_write(region, field_value);
489 if (result != kPmpRegionConfigureOk) {
490 return (pmp_region_configure_napot_result_t)result;
493 return kPmpRegionConfigureNapotOk;
496 pmp_region_configure_result_t pmp_region_configure_tor(
498 uintptr_t address_start, uintptr_t address_end) {
499 if (region_end >= PMP_REGIONS_NUM) {
500 return kPmpRegionConfigureBadRegion;
503 if (region_end == 0 && address_start > 0) {
504 return kPmpRegionConfigureBadAddress;
507 if (region_end > 0 && !pmp_address_aligned(address_start)) {
508 return kPmpRegionConfigureBadAddress;
511 if (!pmp_address_aligned(address_end)) {
512 return kPmpRegionConfigureBadAddress;
515 uint32_t field_value = 0;
516 if (!pmp_cfg_permissions_set(config.
permissions, &field_value)) {
517 return kPmpRegionConfigureError;
520 pmp_cfg_mode_lock_set(config.
lock, &field_value);
523 PMP_CFG_CSR_MODE_TOR);
527 if (region_end != 0) {
528 pmp_region_configure_result_t result =
529 pmp_csr_address_write(region_end - 1, address_start);
530 if (result != kPmpRegionConfigureOk) {
535 pmp_region_configure_result_t result =
536 pmp_csr_address_write(region_end, address_end);
537 if (result != kPmpRegionConfigureOk) {
541 result = pmp_csr_cfg_field_write(region_end, field_value);
542 if (result != kPmpRegionConfigureOk) {
546 return kPmpRegionConfigureOk;
549 pmp_region_configure_result_t pmp_region_is_configured(
550 pmp_region_index_t region,
bool *configured) {
551 if (region >= PMP_REGIONS_NUM) {
552 return kPmpRegionConfigureBadRegion;
555 if (configured == NULL) {
556 return kPmpRegionConfigureBadArg;
559 uint32_t field_value;
560 pmp_region_configure_result_t result =
561 pmp_csr_cfg_field_read(region, &field_value);
562 if (result != kPmpRegionConfigureOk) {
566 *configured = field_value != 0;
568 return kPmpRegionConfigureOk;
571 pmp_region_configure_result_t pmp_region_lock_status_get(
572 pmp_region_index_t region, pmp_region_lock_t *lock) {
573 if (region >= PMP_REGIONS_NUM) {
574 return kPmpRegionConfigureBadRegion;
578 return kPmpRegionConfigureBadArg;
581 uint32_t field_value;
582 pmp_region_configure_result_t result =
583 pmp_csr_cfg_field_read(region, &field_value);
584 if (result != kPmpRegionConfigureOk) {
589 *lock = flag ? kPmpRegionLockLocked : kPmpRegionLockUnlocked;
591 return kPmpRegionConfigureOk;