Skip to content

Commit

Permalink
Merge patch series "riscv: Userspace pointer masking and tagged addre…
Browse files Browse the repository at this point in the history
…ss ABI"

Samuel Holland <samuel.holland@sifive.com> says:

RISC-V defines three extensions for pointer masking[1]:
 - Smmpm: configured in M-mode, affects M-mode
 - Smnpm: configured in M-mode, affects the next lower mode (S or U-mode)
 - Ssnpm: configured in S-mode, affects the next lower mode (VS, VU, or U-mode)

This series adds support for configuring Smnpm or Ssnpm (depending on
which privilege mode the kernel is running in) to allow pointer masking
in userspace (VU or U-mode), extending the PR_SET_TAGGED_ADDR_CTRL API
from arm64. Unlike arm64 TBI, userspace pointer masking is not enabled
by default on RISC-V. Additionally, the tag width (referred to as PMLEN)
is variable, so userspace needs to ask the kernel for a specific tag
width, which is interpreted as a lower bound on the number of tag bits.

This series also adds support for a tagged address ABI similar to arm64
and x86. Since accesses from the kernel to user memory use the kernel's
pointer masking configuration, not the user's, the kernel must untag
user pointers in software before dereferencing them. And since the tag
width is variable, as with LAM on x86, it must be kept the same across
all threads in a process so untagged_addr_remote() can work.

[1]: https://github.com/riscv/riscv-j-extension/raw/d70011dde6c2/zjpm-spec.pdf

* b4-shazam-merge:
  KVM: riscv: selftests: Add Smnpm and Ssnpm to get-reg-list test
  RISC-V: KVM: Allow Smnpm and Ssnpm extensions for guests
  riscv: hwprobe: Export the Supm ISA extension
  riscv: selftests: Add a pointer masking test
  riscv: Allow ptrace control of the tagged address ABI
  riscv: Add support for the tagged address ABI
  riscv: Add support for userspace pointer masking
  riscv: Add CSR definitions for pointer masking
  riscv: Add ISA extension parsing for pointer masking
  dt-bindings: riscv: Add pointer masking ISA extensions

Link: https://lore.kernel.org/r/20241016202814.4061541-1-samuel.holland@sifive.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
  • Loading branch information
Palmer Dabbelt committed Oct 24, 2024
2 parents ce16531 + 036a140 commit 075fde5
Show file tree
Hide file tree
Showing 25 changed files with 712 additions and 7 deletions.
3 changes: 3 additions & 0 deletions Documentation/arch/riscv/hwprobe.rst
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ The following keys are defined:
ratified in commit 98918c844281 ("Merge pull request #1217 from
riscv/zawrs") of riscv-isa-manual.

* :c:macro:`RISCV_HWPROBE_EXT_SUPM`: The Supm extension is supported as
defined in version 1.0 of the RISC-V Pointer Masking extensions.

* :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated. Returns similar values to
:c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
mistakenly classified as a bitmask rather than a value.
Expand Down
16 changes: 16 additions & 0 deletions Documentation/arch/riscv/uabi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,19 @@ Misaligned accesses
Misaligned scalar accesses are supported in userspace, but they may perform
poorly. Misaligned vector accesses are only supported if the Zicclsm extension
is supported.

Pointer masking
---------------

Support for pointer masking in userspace (the Supm extension) is provided via
the ``PR_SET_TAGGED_ADDR_CTRL`` and ``PR_GET_TAGGED_ADDR_CTRL`` ``prctl()``
operations. Pointer masking is disabled by default. To enable it, userspace
must call ``PR_SET_TAGGED_ADDR_CTRL`` with the ``PR_PMLEN`` field set to the
number of mask/tag bits needed by the application. ``PR_PMLEN`` is interpreted
as a lower bound; if the kernel is unable to satisfy the request, the
``PR_SET_TAGGED_ADDR_CTRL`` operation will fail. The actual number of tag bits
is returned in ``PR_PMLEN`` by the ``PR_GET_TAGGED_ADDR_CTRL`` operation.

Additionally, when pointer masking is enabled (``PR_PMLEN`` is greater than 0),
a tagged address ABI is supported, with the same interface and behavior as
documented for AArch64 (Documentation/arch/arm64/tagged-address-abi.rst).
18 changes: 18 additions & 0 deletions Documentation/devicetree/bindings/riscv/extensions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ properties:
changes to interrupts as frozen at commit ccbddab ("Merge pull
request #42 from riscv/jhauser-2023-RC4") of riscv-aia.
- const: smmpm
description: |
The standard Smmpm extension for M-mode pointer masking as
ratified at commit d70011dde6c2 ("Update to ratified state")
of riscv-j-extension.
- const: smnpm
description: |
The standard Smnpm extension for next-mode pointer masking as
ratified at commit d70011dde6c2 ("Update to ratified state")
of riscv-j-extension.
- const: smstateen
description: |
The standard Smstateen extension for controlling access to CSRs
Expand All @@ -147,6 +159,12 @@ properties:
and mode-based filtering as ratified at commit 01d1df0 ("Add ability
to manually trigger workflow. (#2)") of riscv-count-overflow.
- const: ssnpm
description: |
The standard Ssnpm extension for next-mode pointer masking as
ratified at commit d70011dde6c2 ("Update to ratified state")
of riscv-j-extension.
- const: sstc
description: |
The standard Sstc supervisor-level extension for time compare as
Expand Down
11 changes: 11 additions & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,17 @@ config RISCV_ISA_C

If you don't know what to do here, say Y.

config RISCV_ISA_SUPM
bool "Supm extension for userspace pointer masking"
depends on 64BIT
default y
help
Add support for pointer masking in userspace (Supm) when the
underlying hardware extension (Smnpm or Ssnpm) is detected at boot.

If this option is disabled, userspace will be unable to use
the prctl(PR_{SET,GET}_TAGGED_ADDR_CTRL) API.

config RISCV_ISA_SVNAPOT
bool "Svnapot extension support for supervisor mode NAPOT pages"
depends on 64BIT && MMU
Expand Down
16 changes: 16 additions & 0 deletions arch/riscv/include/asm/csr.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@

/* HSTATUS flags */
#ifdef CONFIG_64BIT
#define HSTATUS_HUPMM _AC(0x3000000000000, UL)
#define HSTATUS_HUPMM_PMLEN_0 _AC(0x0000000000000, UL)
#define HSTATUS_HUPMM_PMLEN_7 _AC(0x2000000000000, UL)
#define HSTATUS_HUPMM_PMLEN_16 _AC(0x3000000000000, UL)
#define HSTATUS_VSXL _AC(0x300000000, UL)
#define HSTATUS_VSXL_SHIFT 32
#endif
Expand Down Expand Up @@ -195,6 +199,10 @@
/* xENVCFG flags */
#define ENVCFG_STCE (_AC(1, ULL) << 63)
#define ENVCFG_PBMTE (_AC(1, ULL) << 62)
#define ENVCFG_PMM (_AC(0x3, ULL) << 32)
#define ENVCFG_PMM_PMLEN_0 (_AC(0x0, ULL) << 32)
#define ENVCFG_PMM_PMLEN_7 (_AC(0x2, ULL) << 32)
#define ENVCFG_PMM_PMLEN_16 (_AC(0x3, ULL) << 32)
#define ENVCFG_CBZE (_AC(1, UL) << 7)
#define ENVCFG_CBCFE (_AC(1, UL) << 6)
#define ENVCFG_CBIE_SHIFT 4
Expand All @@ -216,6 +224,12 @@
#define SMSTATEEN0_SSTATEEN0_SHIFT 63
#define SMSTATEEN0_SSTATEEN0 (_ULL(1) << SMSTATEEN0_SSTATEEN0_SHIFT)

/* mseccfg bits */
#define MSECCFG_PMM ENVCFG_PMM
#define MSECCFG_PMM_PMLEN_0 ENVCFG_PMM_PMLEN_0
#define MSECCFG_PMM_PMLEN_7 ENVCFG_PMM_PMLEN_7
#define MSECCFG_PMM_PMLEN_16 ENVCFG_PMM_PMLEN_16

/* symbolic CSR names: */
#define CSR_CYCLE 0xc00
#define CSR_TIME 0xc01
Expand Down Expand Up @@ -382,6 +396,8 @@
#define CSR_MIP 0x344
#define CSR_PMPCFG0 0x3a0
#define CSR_PMPADDR0 0x3b0
#define CSR_MSECCFG 0x747
#define CSR_MSECCFGH 0x757
#define CSR_MVENDORID 0xf11
#define CSR_MARCHID 0xf12
#define CSR_MIMPID 0xf13
Expand Down
5 changes: 5 additions & 0 deletions arch/riscv/include/asm/hwcap.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@
#define RISCV_ISA_EXT_ZCMOP 84
#define RISCV_ISA_EXT_ZAWRS 85
#define RISCV_ISA_EXT_SVVPTC 86
#define RISCV_ISA_EXT_SMMPM 87
#define RISCV_ISA_EXT_SMNPM 88
#define RISCV_ISA_EXT_SSNPM 89

#define RISCV_ISA_EXT_XLINUXENVCFG 127

Expand All @@ -101,8 +104,10 @@

#ifdef CONFIG_RISCV_M_MODE
#define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SMAIA
#define RISCV_ISA_EXT_SUPM RISCV_ISA_EXT_SMNPM
#else
#define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SSAIA
#define RISCV_ISA_EXT_SUPM RISCV_ISA_EXT_SSNPM
#endif

#endif /* _ASM_RISCV_HWCAP_H */
7 changes: 7 additions & 0 deletions arch/riscv/include/asm/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,16 @@ typedef struct {
#ifdef CONFIG_BINFMT_ELF_FDPIC
unsigned long exec_fdpic_loadmap;
unsigned long interp_fdpic_loadmap;
#endif
unsigned long flags;
#ifdef CONFIG_RISCV_ISA_SUPM
u8 pmlen;
#endif
} mm_context_t;

/* Lock the pointer masking mode because this mm is multithreaded */
#define MM_CONTEXT_LOCK_PMLEN 0

#define cntx2asid(cntx) ((cntx) & SATP_ASID_MASK)
#define cntx2version(cntx) ((cntx) & ~SATP_ASID_MASK)

Expand Down
13 changes: 13 additions & 0 deletions arch/riscv/include/asm/mmu_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next,
static inline void activate_mm(struct mm_struct *prev,
struct mm_struct *next)
{
#ifdef CONFIG_RISCV_ISA_SUPM
next->context.pmlen = 0;
#endif
switch_mm(prev, next, NULL);
}

Expand All @@ -30,11 +33,21 @@ static inline int init_new_context(struct task_struct *tsk,
#ifdef CONFIG_MMU
atomic_long_set(&mm->context.id, 0);
#endif
if (IS_ENABLED(CONFIG_RISCV_ISA_SUPM))
clear_bit(MM_CONTEXT_LOCK_PMLEN, &mm->context.flags);
return 0;
}

DECLARE_STATIC_KEY_FALSE(use_asid_allocator);

#ifdef CONFIG_RISCV_ISA_SUPM
#define mm_untag_mask mm_untag_mask
static inline unsigned long mm_untag_mask(struct mm_struct *mm)
{
return -1UL >> mm->context.pmlen;
}
#endif

#include <asm-generic/mmu_context.h>

#endif /* _ASM_RISCV_MMU_CONTEXT_H */
8 changes: 8 additions & 0 deletions arch/riscv/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val);
#define RISCV_SET_ICACHE_FLUSH_CTX(arg1, arg2) riscv_set_icache_flush_ctx(arg1, arg2)
extern int riscv_set_icache_flush_ctx(unsigned long ctx, unsigned long per_thread);

#ifdef CONFIG_RISCV_ISA_SUPM
/* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */
long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg);
long get_tagged_addr_ctrl(struct task_struct *task);
#define SET_TAGGED_ADDR_CTRL(arg) set_tagged_addr_ctrl(current, arg)
#define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl(current)
#endif

#endif /* __ASSEMBLY__ */

#endif /* _ASM_RISCV_PROCESSOR_H */
11 changes: 11 additions & 0 deletions arch/riscv/include/asm/switch_to.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ static __always_inline bool has_fpu(void) { return false; }
#define __switch_to_fpu(__prev, __next) do { } while (0)
#endif

static inline void envcfg_update_bits(struct task_struct *task,
unsigned long mask, unsigned long val)
{
unsigned long envcfg;

envcfg = (task->thread.envcfg & ~mask) | val;
task->thread.envcfg = envcfg;
if (task == current)
csr_write(CSR_ENVCFG, envcfg);
}

static inline void __switch_to_envcfg(struct task_struct *next)
{
asm volatile (ALTERNATIVE("nop", "csrw " __stringify(CSR_ENVCFG) ", %0",
Expand Down
43 changes: 38 additions & 5 deletions arch/riscv/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,41 @@
#define _ASM_RISCV_UACCESS_H

#include <asm/asm-extable.h>
#include <asm/cpufeature.h>
#include <asm/pgtable.h> /* for TASK_SIZE */

#ifdef CONFIG_RISCV_ISA_SUPM
static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigned long addr)
{
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) {
u8 pmlen = mm->context.pmlen;

/* Virtual addresses are sign-extended; physical addresses are zero-extended. */
if (IS_ENABLED(CONFIG_MMU))
return (long)(addr << pmlen) >> pmlen;
else
return (addr << pmlen) >> pmlen;
}

return addr;
}

#define untagged_addr(addr) ({ \
unsigned long __addr = (__force unsigned long)(addr); \
(__force __typeof__(addr))__untagged_addr_remote(current->mm, __addr); \
})

#define untagged_addr_remote(mm, addr) ({ \
unsigned long __addr = (__force unsigned long)(addr); \
mmap_assert_locked(mm); \
(__force __typeof__(addr))__untagged_addr_remote(mm, __addr); \
})

#define access_ok(addr, size) likely(__access_ok(untagged_addr(addr), size))
#else
#define untagged_addr(addr) (addr)
#endif

/*
* User space memory access functions
*/
Expand Down Expand Up @@ -130,7 +163,7 @@ do { \
*/
#define __get_user(x, ptr) \
({ \
const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
long __gu_err = 0; \
\
__chk_user_ptr(__gu_ptr); \
Expand Down Expand Up @@ -246,7 +279,7 @@ do { \
*/
#define __put_user(x, ptr) \
({ \
__typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
__typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
__typeof__(*__gu_ptr) __val = (x); \
long __pu_err = 0; \
\
Expand Down Expand Up @@ -293,13 +326,13 @@ unsigned long __must_check __asm_copy_from_user(void *to,
static inline unsigned long
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
{
return __asm_copy_from_user(to, from, n);
return __asm_copy_from_user(to, untagged_addr(from), n);
}

static inline unsigned long
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
{
return __asm_copy_to_user(to, from, n);
return __asm_copy_to_user(untagged_addr(to), from, n);
}

extern long strncpy_from_user(char *dest, const char __user *src, long count);
Expand All @@ -314,7 +347,7 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)
{
might_fault();
return access_ok(to, n) ?
__clear_user(to, n) : n;
__clear_user(untagged_addr(to), n) : n;
}

#define __get_kernel_nofault(dst, src, type, err_label) \
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/include/uapi/asm/hwprobe.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ struct riscv_hwprobe {
#define RISCV_HWPROBE_EXT_ZCF (1ULL << 46)
#define RISCV_HWPROBE_EXT_ZCMOP (1ULL << 47)
#define RISCV_HWPROBE_EXT_ZAWRS (1ULL << 48)
#define RISCV_HWPROBE_EXT_SUPM (1ULL << 49)
#define RISCV_HWPROBE_KEY_CPUPERF_0 5
#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0)
Expand Down
2 changes: 2 additions & 0 deletions arch/riscv/include/uapi/asm/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ enum KVM_RISCV_ISA_EXT_ID {
KVM_RISCV_ISA_EXT_ZCF,
KVM_RISCV_ISA_EXT_ZCMOP,
KVM_RISCV_ISA_EXT_ZAWRS,
KVM_RISCV_ISA_EXT_SMNPM,
KVM_RISCV_ISA_EXT_SSNPM,
KVM_RISCV_ISA_EXT_MAX,
};

Expand Down
3 changes: 3 additions & 0 deletions arch/riscv/kernel/cpufeature.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,12 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_BUNDLE(zvksg, riscv_zvksg_bundled_exts),
__RISCV_ISA_EXT_DATA(zvkt, RISCV_ISA_EXT_ZVKT),
__RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
__RISCV_ISA_EXT_DATA(smmpm, RISCV_ISA_EXT_SMMPM),
__RISCV_ISA_EXT_SUPERSET(smnpm, RISCV_ISA_EXT_SMNPM, riscv_xlinuxenvcfg_exts),
__RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN),
__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
__RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
Expand Down
Loading

0 comments on commit 075fde5

Please sign in to comment.