RISC-V ISA Specification. Working draft, subject to change.
Adam Zabrocki, Lee Campbell, Martin Maas, RISC-V TEE and J Extension Task Groups
Contributors: Jecel Assumpcao, Allen Baum, Paul Donahue, Greg Favor, Andy Glew, John Ingalls, Christos Kotselidis, Ian Rogers, Josh Scheid, Kostya Serebryany, Boris Shingarov, Foivos Zakkak, Members of the TEE and J Extension Task Groups
RISC-V Pointer Masking (PM) is a feature which provides a possibility of implementing “memory tagging” by ignoring various bits (defined by mask) of the effective address (virtual or physical) on RV128, RV64 and RV32.
Effective address is an address generated by the address generation logic before it is sent to the memory subsystem. As such, there is no special handling of physical vs. virtual memory at the software level.
Memory tagging (MT) is a technique which can significantly improve the memory safety state of any application (including code running in more privileged modes). MT can be fully implemented in the hardware or partially hardware assisted. However, both implementations require a PM feature to be enabled to not overwhelm the performance.
General idea of MT is based on assigning a tag to every granule of memory (a small, e.g. 16-byte, naturally aligned memory region). All accesses to memory must be made via a pointer with the correct tag. Use of an incorrect tag is noted and the monitor software can choose what to do with such a situation (e.g. could be killing the process, or just report it to the user immediately). To be able to store the tag in every memory pointer (poisoning the pointer) and correctly using it in running applications without significant performance impact, PM is necessary.
This document proposes an extension for RISC-V called PM (Pointer Masking) which in the future might be enhanced for implementing a full hardware memory tagging.
We propose to add:
-
new PM configuration CSR register called MMTE (Memory Tagging Extension)
-
new PM pointer masking CSR register for each privilege mode called MPMMASK (Pointer Masking Mask)
-
new PM pointer base CSR register for each privilege mode called MPMBASE (Pointer Masking Base)
Restricted views of the mmte register appear as the smte, vsmte and umte registers in the HS/S-mode, VS-mode and (V)U-mode ISAs respectively.
Each privilege mode has own copy of pointer masking CSR register. It appears as the mpmmask, spmmask, vspmmask and upmmask registers in the M-mode, HS/S-mode, VS-mode and (V)U-mode ISAs, respectively.
Each privilege mode has its own copy of pointer base CSR register. It appears as the mpmbase, spmbase, vspmbase and upmbase registers in the M-mode, HS/S-mode, VS-mode and (V)U-mode ISAs, respectively.
The purpose of the mpmmask register is to be able to precisely define a mask whose bits of the effective address are ignored. The actual address can be calculated by using requested address and mpmmask register.
Additionally, mpmbase register can be defined, allowing to replace those bits of the actual_address which are defined to be masked by mpmmask. mpmbase can be configured to replace only the subset of the masked bits, and the remaining are still ignored and can be used for any purpose (e.g. memory tagging).
If mpmbase register is set (has value other than zero), actual address can be calculated by using requested address, mpmmask and mpmbase register:
actual_address = (requested_address & ~mpmmask) | mpmbase
mpmbase register can be read-only and hardwired to 0. In such case, the actual address will be calculated only by using requested address and mpmmask register.
When PM extension is enabled, mpmmask and mpmbase registers allow to implement in-process isolation feature. That feature allows for each thread to be isolated to a given block of the address space. It can be used to isolate untrusted code within a process. A high-level concept can be seen on Picture 1.
MMTE layout can be found in Figure 1a, 1b, 1c and 1d for M, HS/S, VS and (V)U-mode.
MPMMASK layout can be found in Figure 2a, 2b, 2c and 2d for M, HS/S, VS and (V)U-mode.
MPMBASE layout can be found in Figure 3a, 3b, 3c and 3d for M, HS/S, VS and (V)U-mode.
Table 1 explains the meaning of PM bits for RV32, RV64 and RV128.
mmte[XLEN-1:6] | mmte[5:4] | mmte[3:2] | mmte[1:0] | WPRI |
---|
smte[XLEN-1:4] | smte[3:2] | smte[1:0] | WPRI |
---|
vsmte[XLEN-1:4] | vsmte[3:2] | vsmte[1:0] |
---|---|---|
WPRI |
VS-mode PM |
VU-mode PM |
umte[XLEN-1:2] | umte[1:0] |
---|---|
WPRI |
(V)U-mode PM |
PM Bits | Name | Meaning |
---|---|---|
PM[0:0] |
PM.Enabled |
0 – PM is disabled (default) |
PM[1:1] |
PM.Current |
0 – xPMMASK and xPMBASE registers can only be modified by the higher privilege mode |
mpmmask[XLEN-1:0] |
---|
MASK |
spmmask[XLEN-1:0] |
---|
MASK |
vspmmask[XLEN-1:0] |
---|
MASK |
upmmask[XLEN-1:0] |
---|
MASK |
mpmbase[XLEN-1:0] |
---|
BASE |
spmbase[XLEN-1:0] |
---|
BASE |
vspmbase[XLEN-1:0] |
---|
BASE |
upmbase[XLEN-1:0] |
---|
BASE |
xMTE register fulfills two-fold function:
-
Can only be programmable by more privileged mode (unless PM.Current bit is enabled)
-
Performs status register function for the current privilege mode
PM bits from MMTE register are accessible in all modes ((V)U/VS/HS/S/M) and can be read to query if the PM feature is currently enforced. By default, only higher privileged code can set the value for PM bits. However, higher privileged code can enable PM.Current bit for lower privileged code. In such scenario, current privilege code has a possibility to self-manage its own configuration of PM bits.
By default, the current CPU mode is using xPMMASK, xPMBASE and PM bits corresponding to it. When CPU is switching the mode, corresponding pair of xPMMASK, xPMBASE and PM bits are used. Special carefulness is necessary when VU and U mode are available. If virtualization extension is enabled, and hypervisor is not using xPMMASK / xPMBASE CSRs for its U-mode then context switches these registers when it context switches between VMs. If a hypervisor is using xPMMASK / xPMBASE CSRs for its U-mode, then it switches in its own pair before dropping down to U-mode. Later, HS/S-mode context switches in the pair for the VM that it returns to.
If higher privileged code needs to use xPMMASK and xPMBASE from the lower privilege mode, there are two possible solutions:
1. Emulate equation 1. purely in software using xPMMASK and xPMBASE CSRs from the desired privilege mode.
2. If PM.Current is enabled it is possible to save the state of the current xPMMASK and xPMBASE CSRs and temporarily replace them with the desired one. At the end, original values can be restored.
MPMMASK register fully two-fold function:
-
Based on PM bits configuration, it can be programmable by the higher privilege mode or by the current privilege mode
-
Performs status register function for the current privilege mode
MPMBASE register fully two-fold function:
-
Based on PM bits configuration, it can be programmable by the higher privilege mode or by the current privilege mode
-
Performs status register function for the current privilege mode
Any write access would be ignored if performed to the current xPMMASK, xPMBASE and MMTE CSR registers and PM.Current is disabled.
PM extension allows various flavors of implementation. If PM is not desired in specific RISC-V mode, appropriate CSRs could be read-only and hardwired to 0.