forked from apache/nuttx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
mpfs_mpu: Add driver to set MPUCFG registers
MPUCFG registers are used to enforce memory protection for DMA master devices.
- Loading branch information
Showing
4 changed files
with
332 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
/**************************************************************************** | ||
* arch/risc-v/src/mpfs/mpfs_mpu.c | ||
* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. The | ||
* ASF licenses this file to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance with the | ||
* License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
* | ||
****************************************************************************/ | ||
|
||
/**************************************************************************** | ||
* Included Files | ||
****************************************************************************/ | ||
|
||
#include <nuttx/config.h> | ||
|
||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include <errno.h> | ||
|
||
#include <arch/csr.h> | ||
|
||
#include <nuttx/lib/math32.h> | ||
|
||
#include "riscv_internal.h" | ||
#include "mpfs_memorymap.h" | ||
|
||
#include "hardware/mpfs_mpucfg.h" | ||
|
||
/**************************************************************************** | ||
* Pre-processor Definitions | ||
****************************************************************************/ | ||
|
||
/* MPUCFG entry is 64-bits */ | ||
|
||
#define MPFS_MPUCFG_WIDTH 64 | ||
|
||
/* Mode bits [63:56] */ | ||
|
||
#define MPFS_MPUCFG_MODE_SHIFT 56 | ||
#define MPFS_MPUCFG_MODE_WIDTH 8 | ||
#define MPFS_MPUCFG_MODE_MASK \ | ||
(((1ul << MPFS_MPUCFG_MODE_WIDTH) - 1) << MPFS_MPUCFG_MODE_SHIFT) | ||
|
||
/* PMP entry bits [35:0] */ | ||
|
||
#define MPFS_MPUCFG_PMP_SHIFT 0 | ||
#define MPFS_MPUCFG_PMP_WIDTH 36 | ||
#define MPFS_MPUCFG_PMP_MASK \ | ||
(((1ul << MPFS_MPUCFG_PMP_WIDTH) - 1) << MPFS_MPUCFG_PMP_SHIFT) | ||
|
||
/* Encode the MPUCFG register value */ | ||
|
||
#define MPFS_MPUCFG_ENCODE(mode, napot) \ | ||
(((mode << MPFS_MPUCFG_MODE_SHIFT) & MPFS_MPUCFG_MODE_MASK) | \ | ||
((napot << MPFS_MPUCFG_PMP_SHIFT) & MPFS_MPUCFG_PMP_MASK)) | ||
|
||
/* Decode the MPUCFG register value */ | ||
|
||
#define MPFS_MPUCFG_DECODE(reg, mode, napot) \ | ||
do \ | ||
{ \ | ||
uintptr_t val = getreg64(reg); \ | ||
*(mode) = (val & MPFS_MPUCFG_MODE_MASK) >> MPFS_MPUCFG_MODE_SHIFT; \ | ||
*(napot) = (val & MPFS_MPUCFG_PMP_MASK) >> MPFS_MPUCFG_PMP_SHIFT; \ | ||
} \ | ||
while(0) | ||
|
||
/**************************************************************************** | ||
* Private Functions | ||
****************************************************************************/ | ||
|
||
/**************************************************************************** | ||
* Name: napot_decode | ||
* | ||
* Description: | ||
* Decode base and size from NAPOT value | ||
* | ||
* Input Parameters: | ||
* val - Value to decode. | ||
* size - Size out. | ||
* | ||
* Returned Value: | ||
* Base address | ||
* | ||
****************************************************************************/ | ||
|
||
static void napot_decode(uintptr_t val, uintptr_t *base, uintptr_t *size) | ||
{ | ||
uintptr_t mask = (uintptr_t)(-1) >> 1; | ||
uintptr_t pot = MPFS_MPUCFG_WIDTH + 2; | ||
|
||
while (mask) | ||
{ | ||
if ((val & mask) == mask) | ||
{ | ||
break; | ||
} | ||
|
||
pot--; | ||
mask >>= 1; | ||
} | ||
|
||
*size = UINT64_C(1) << pot; | ||
*base = (val & ~mask) << 2; | ||
} | ||
|
||
/**************************************************************************** | ||
* Public Functions | ||
****************************************************************************/ | ||
|
||
/**************************************************************************** | ||
* Name: mpfs_mpu_set | ||
* | ||
* Description: | ||
* Set value to MPFS MPUCFG register. | ||
* | ||
* Input Parameters: | ||
* reg - The MPUCFG register to write. | ||
* perm - The region permissions. | ||
* base - The base address of the region. | ||
* size - The length of the region. | ||
* | ||
* Note: | ||
* Only NAPOT encoded regions are supported, thus the base address and | ||
* size must align with each other. | ||
* | ||
* Returned Value: | ||
* 0 on success; negated error on failure | ||
* | ||
****************************************************************************/ | ||
|
||
int mpfs_mpu_set(uintptr_t reg, uintptr_t perm, uintptr_t base, | ||
uintptr_t size) | ||
{ | ||
uintptr_t mode; | ||
uintptr_t napot; | ||
|
||
/* Read the the permission and napot fields */ | ||
|
||
MPFS_MPUCFG_DECODE(reg, &mode, &napot); | ||
|
||
/* First, check that the register is not already configured */ | ||
|
||
if ((mode & PMPCFG_L) != 0) | ||
{ | ||
/* The entry is locked, get out */ | ||
|
||
return -EACCES; | ||
} | ||
|
||
/* Base must be word aligned, minimum size is 4K */ | ||
|
||
if ((base & 0x07) != 0 || size < 0x1000) | ||
{ | ||
return -EINVAL; | ||
} | ||
|
||
/* Make sure the base + size are NAPOT encodable */ | ||
|
||
if ((base & ((UINT64_C(1) << log2ceil(size)) - 1)) != 0) | ||
{ | ||
/* The start address is not properly aligned with size */ | ||
|
||
return -EINVAL; | ||
} | ||
|
||
/* Sanity check the register */ | ||
|
||
if (reg < MPFS_MPUCFG_BASE || reg >= MPFS_MPUCFG_END) | ||
{ | ||
return -EINVAL; | ||
} | ||
|
||
/* Calculate mode (RWX), only NAPOT encoding is supported */ | ||
|
||
mode = (perm & PMPCFG_RWX_MASK) | PMPCFG_A_NAPOT; | ||
|
||
/* Do the NAPOT encoding */ | ||
|
||
napot = (base >> 2) | ((size - 1) >> 3); | ||
|
||
/* Then set the value */ | ||
|
||
putreg64(MPFS_MPUCFG_ENCODE(mode, napot), reg); | ||
|
||
return OK; | ||
} | ||
|
||
/**************************************************************************** | ||
* Name: mpfs_mpu_access_ok | ||
* | ||
* Description: | ||
* Check if MPFS MPUCFG access is OK for register. | ||
* | ||
* Input Parameters: | ||
* reg - The MPUCFG register to check. | ||
* perm - The region permissions. | ||
* base - The base address of the region. | ||
* size - The length of the region. | ||
* | ||
* Returned Value: | ||
* true if access OK; false if not | ||
* | ||
****************************************************************************/ | ||
|
||
bool mpfs_mpu_access_ok(uintptr_t reg, uintptr_t perm, uintptr_t base, | ||
uintptr_t size) | ||
{ | ||
uintptr_t mode; | ||
uintptr_t napot; | ||
uintptr_t reg_base; | ||
uintptr_t reg_size; | ||
|
||
/* Read the the permission and napot fields */ | ||
|
||
MPFS_MPUCFG_DECODE(reg, &mode, &napot); | ||
|
||
/* Check for permission match */ | ||
|
||
if ((mode & PMPCFG_RWX_MASK) != perm) | ||
{ | ||
return false; | ||
} | ||
|
||
/* Decode the napot field */ | ||
|
||
napot_decode(napot, ®_base, ®_size); | ||
|
||
/* Then check if the area fits */ | ||
|
||
return (base >= reg_base && (base + size) <= (reg_base + reg_size)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/**************************************************************************** | ||
* arch/risc-v/src/mpfs/mpfs_mpu.h | ||
* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. The | ||
* ASF licenses this file to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance with the | ||
* License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
* | ||
****************************************************************************/ | ||
|
||
#ifndef __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H | ||
#define __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H | ||
|
||
/**************************************************************************** | ||
* Included Files | ||
****************************************************************************/ | ||
|
||
#include <stdint.h> | ||
#include <stdbool.h> | ||
|
||
/**************************************************************************** | ||
* Public Function Prototypes | ||
****************************************************************************/ | ||
|
||
/**************************************************************************** | ||
* Name: mpfs_mpu_set | ||
* | ||
* Description: | ||
* Set value to MPFS MPUCFG register. | ||
* | ||
* Input Parameters: | ||
* reg - The MPUCFG register to write. | ||
* perm - The region permissions. | ||
* base - The base address of the region. | ||
* size - The length of the region. | ||
* | ||
* Note: | ||
* Only NAPOT encoded regions are supported, thus the base address and | ||
* size must align with each other. | ||
* | ||
* Returned Value: | ||
* 0 on success; negated error on failure | ||
* | ||
****************************************************************************/ | ||
|
||
int mpfs_mpu_set(uintptr_t reg, uintptr_t perm, uintptr_t base, | ||
uintptr_t size); | ||
|
||
/**************************************************************************** | ||
* Name: mpfs_mpu_access_ok | ||
* | ||
* Description: | ||
* Check if MPFS MPUCFG access is OK for register. | ||
* | ||
* Input Parameters: | ||
* reg - The MPUCFG register to check. | ||
* perm - The region permissions. | ||
* base - The base address of the region. | ||
* size - The length of the region. | ||
* | ||
* Returned Value: | ||
* true if access OK; false if not | ||
* | ||
****************************************************************************/ | ||
|
||
bool mpfs_mpu_access_ok(uintptr_t reg, uintptr_t perm, uintptr_t base, | ||
uintptr_t size); | ||
|
||
#endif /* __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H */ |