1、物理内存保护机制
参考博客:《RISC-V架构——物理内存属性和物理内存保护》;
2、pmp_set函数源码
int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
unsigned long log2len)
{
int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
unsigned long cfgmask, pmpcfg;
unsigned long addrmask, pmpaddr;
/* check parameters */
if (n >= PMP_COUNT || log2len > __riscv_xlen || log2len < PMP_SHIFT)
return SBI_EINVAL;
/* 计算配置项所在pmpcfg是哪一个,已经配置项在pmpcfg中的偏移量 */
#if __riscv_xlen == 32
pmpcfg_csr = CSR_PMPCFG0 + (n >> 2);
pmpcfg_shift = (n & 3) << 3;
#elif __riscv_xlen == 64
pmpcfg_csr = (CSR_PMPCFG0 + (n >> 2)) & ~1;
pmpcfg_shift = (n & 7) << 3;
#else
# error "Unexpected __riscv_xlen"
#endif
pmpaddr_csr = CSR_PMPADDR0 + n;
//清除配置项里地址匹配模式
prot &= ~PMP_A;
//如果是要设置的物理内存是4个字节则用NA4模式,否则用NAPOT模式
prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
cfgmask = ~(0xffUL << pmpcfg_shift);
//读取出对于pmpcfg寄存器的值,并且将对应表项清零
pmpcfg = (csr_read_num(pmpcfg_csr) & cfgmask);
//设置对应表项
pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
/* 配置pmp地址寄存器,如果要设置的物理地址范围是4字节 */
if (log2len == PMP_SHIFT) {
pmpaddr = (addr >> PMP_SHIFT);
} else {
if (log2len == __riscv_xlen) { //__riscv_xlen是寄存器的位宽,相等则是要设置整个物理地址空间
pmpaddr = -1UL;
} else {
addrmask = (1UL << (log2len - PMP_SHIFT)) - 1;
pmpaddr = ((addr >> PMP_SHIFT) & ~addrmask); //将要设置的物理地址范围左移2位,然后低(log2len - 2)位清0
pmpaddr |= (addrmask >> 1); //设置pmp地址寄存器,此时pmpaddr寄存器的值,最低位开始有(log2len - 3)个1
}
}
/* 设置pmp表项和pmp地址寄存器 */
csr_write_num(pmpaddr_csr, pmpaddr);
csr_write_num(pmpcfg_csr, pmpcfg);
return 0;
}