From nobody Tue Nov 26 19:56:47 2024 Received: from mail-pg1-f175.google.com (mail-pg1-f175.google.com [209.85.215.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F025321732A for ; Wed, 16 Oct 2024 20:28:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729110506; cv=none; b=QnPOTVAHpAb80vP8kKo9LswC7n6PtK5WX0I4Ku+s3ATqMtLmc5g31KSt7zMFq32DeC5zCYfnG5yG5bz4haB0YgqHlwrvwg5tcrWaVtFMKnOPC/TAchP7InSJ6RP6j2vXbTPSjaNWdLqgT/EigaXh3szH+12vI/HQn2gbFM09w2g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1729110506; c=relaxed/simple; bh=Dc7rEYEgxGD/Cl+SV1SEXcIn3loeLbqoEG/MWrQrS2E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=naJTodIoF/4v2IwYMvlbDo/LXqndeo2Ux043v67TZlNOdEFPs10C05HJRpCZyr6liecdq6FfM1thJ3BoN1WgToC3Yydlcw3l1Xa1z1x9G/elUKEkjY8m0fJPbmN/UpY4y39g6N6VXcfJ3JS0rlxRGnlu+nkydNGNl+QL+PSZnLU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=sifive.com; spf=pass smtp.mailfrom=sifive.com; dkim=pass (2048-bit key) header.d=sifive.com header.i=@sifive.com header.b=AbzV3i4M; arc=none smtp.client-ip=209.85.215.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=sifive.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=sifive.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=sifive.com header.i=@sifive.com header.b="AbzV3i4M" Received: by mail-pg1-f175.google.com with SMTP id 41be03b00d2f7-7e9e38dd5f1so176116a12.0 for ; Wed, 16 Oct 2024 13:28:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; t=1729110504; x=1729715304; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=eo/JV88hOL+S2Nr/0pjLrqapJLfVH6+MO5UxiP8a69U=; b=AbzV3i4MlfktMjd1sJSmVBKoozl6LPKiolvV2GSbkycArD8bzLHTyehjPDDrwUl9h5 /YZdK9IvcyoZROhwD14JsUS5EyVmFs9FuR7bPs6TzxYxd6BC/z7KRNd689xiPp1Gg7C1 4Mq+knkdnpwE7A8ETliW2P+uab/6Bpb1398NcZGo80Im5ExC9nMR9+yF3w9Gixc+9e/D tl3qdJY4oio90dbRa8iQRJsnSWDvrzWOSsenH3ZYyBzWtMPIG2jU2d1baDziMpriOvj6 hrRb0afADwOnlib9wqebn7r1wID36sft7ArlZvMFDvdKlDD73RHllRAHHSnpbEb3nKrk 4VPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729110504; x=1729715304; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=eo/JV88hOL+S2Nr/0pjLrqapJLfVH6+MO5UxiP8a69U=; b=HGVlkwLuxfBXjQQBNYomye1vA9Niqcmn8wPthmYamuFQeHtT2dBTesDSaR56gISwMo 321PwMpRR41Dl4YkVbugXXzVZhWFsnuTGUx+tcwEv0QBQYdEv18NPKG5Ej6xohJ3NsTE ICkRawdwdt2SvyY8aaF6GpStsLf730Q4L28IiStHQ/Y6J4mPM9ctzla/gITeUnhgF5Qv DEaFALB5gWqQUC7vk0xGHe0mQknTYOs7cw7xsDbVdCsJDiIqFebL/oQ/RqVEqQ2i8KKk vHunVJAlrC6erBISjkxh/BHxsxrIuvOXSQvmMfPPHp6/3Iplq6/NPjL/ruE2gSQdqvg7 wn4A== X-Forwarded-Encrypted: i=1; AJvYcCVuozqNQ6CSlnEC9tInDp2f2wljht6//WhSAQgZpBW3TVzjVvgn1sAVGzjEkZkO+7OWtfsa1B9TiUlh71w=@vger.kernel.org X-Gm-Message-State: AOJu0Yz9uKNwMD+CNTrDSMn4xfmG9QLcCoqZ0//eaL2afSDPRkTezXI7 F1hXVnXFQyN8+fsh3OwUWRF7+W1HQMaq6xhYEmVxWoTBObE/CmZF1WeitOr6dRU= X-Google-Smtp-Source: AGHT+IEJIDriZqg0yBJTxMeg1P8T+SpmofcxsatsSbAlwqzSvOscPzTniDFKaKdVE7curJ4vos+ZWw== X-Received: by 2002:a17:90b:881:b0:2e2:a097:bb02 with SMTP id 98e67ed59e1d1-2e3ab7f85a6mr6439669a91.11.1729110504350; Wed, 16 Oct 2024 13:28:24 -0700 (PDT) Received: from sw06.internal.sifive.com ([4.53.31.132]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2e3e08f8f89sm228613a91.38.2024.10.16.13.28.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 16 Oct 2024 13:28:23 -0700 (PDT) From: Samuel Holland To: Palmer Dabbelt , linux-riscv@lists.infradead.org Cc: Catalin Marinas , Atish Patra , linux-kselftest@vger.kernel.org, Rob Herring , "Kirill A . Shutemov" , Shuah Khan , devicetree@vger.kernel.org, Anup Patel , linux-kernel@vger.kernel.org, Jonathan Corbet , kvm-riscv@lists.infradead.org, Conor Dooley , kasan-dev@googlegroups.com, linux-doc@vger.kernel.org, Evgenii Stepanov , Charlie Jenkins , Krzysztof Kozlowski , Samuel Holland Subject: [PATCH v5 04/10] riscv: Add support for userspace pointer masking Date: Wed, 16 Oct 2024 13:27:45 -0700 Message-ID: <20241016202814.4061541-5-samuel.holland@sifive.com> X-Mailer: git-send-email 2.45.1 In-Reply-To: <20241016202814.4061541-1-samuel.holland@sifive.com> References: <20241016202814.4061541-1-samuel.holland@sifive.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" RISC-V supports pointer masking with a variable number of tag bits (which is called "PMLEN" in the specification) and which is configured at the next higher privilege level. Wire up the PR_SET_TAGGED_ADDR_CTRL and PR_GET_TAGGED_ADDR_CTRL prctls so userspace can request a lower bound on the number of tag bits and determine the actual number of tag bits. As with arm64's PR_TAGGED_ADDR_ENABLE, the pointer masking configuration is thread-scoped, inherited on clone() and fork() and cleared on execve(). Reviewed-by: Charlie Jenkins Tested-by: Charlie Jenkins Signed-off-by: Samuel Holland --- Changes in v5: - Document how PR_[SG]ET_TAGGED_ADDR_CTRL are used on RISC-V Changes in v4: - Switch IS_ENABLED back to #ifdef to fix riscv32 build Changes in v3: - Rename CONFIG_RISCV_ISA_POINTER_MASKING to CONFIG_RISCV_ISA_SUPM, since it only controls the userspace part of pointer masking - Use IS_ENABLED instead of #ifdef when possible - Use an enum for the supported PMLEN values - Simplify the logic in set_tagged_addr_ctrl() Changes in v2: - Rebase on riscv/linux.git for-next - Add and use the envcfg_update_bits() helper function - Inline flush_tagged_addr_state() Documentation/arch/riscv/uabi.rst | 12 ++++ arch/riscv/Kconfig | 11 ++++ arch/riscv/include/asm/processor.h | 8 +++ arch/riscv/include/asm/switch_to.h | 11 ++++ arch/riscv/kernel/process.c | 91 ++++++++++++++++++++++++++++++ include/uapi/linux/prctl.h | 5 +- 6 files changed, 137 insertions(+), 1 deletion(-) diff --git a/Documentation/arch/riscv/uabi.rst b/Documentation/arch/riscv/u= abi.rst index 2b420bab0527..ddb8359a46ed 100644 --- a/Documentation/arch/riscv/uabi.rst +++ b/Documentation/arch/riscv/uabi.rst @@ -68,3 +68,15 @@ Misaligned accesses Misaligned scalar accesses are supported in userspace, but they may perform poorly. Misaligned vector accesses are only supported if the Zicclsm exte= nsion 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 t= he +number of mask/tag bits needed by the application. ``PR_PMLEN`` is interpr= eted +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. diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 22dc5ea4196c..0ef449465378 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -531,6 +531,17 @@ config RISCV_ISA_C =20 If you don't know what to do here, say Y. =20 +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 diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/pr= ocessor.h index c1a492508835..5f56eb9d114a 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -178,6 +178,14 @@ extern int set_unalign_ctl(struct task_struct *tsk, un= signed 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); =20 +#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__ */ =20 #endif /* _ASM_RISCV_PROCESSOR_H */ diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/sw= itch_to.h index 9685cd85e57c..94e33216b2d9 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -70,6 +70,17 @@ static __always_inline bool has_fpu(void) { return false= ; } #define __switch_to_fpu(__prev, __next) do { } while (0) #endif =20 +static inline void envcfg_update_bits(struct task_struct *task, + unsigned long mask, unsigned long val) +{ + unsigned long envcfg; + + envcfg =3D (task->thread.envcfg & ~mask) | val; + task->thread.envcfg =3D envcfg; + if (task =3D=3D 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", diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index e3142d8a6e28..200d2ed64dfe 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -7,6 +7,7 @@ * Copyright (C) 2017 SiFive */ =20 +#include #include #include #include @@ -180,6 +181,10 @@ void flush_thread(void) memset(¤t->thread.vstate, 0, sizeof(struct __riscv_v_ext_state)); clear_tsk_thread_flag(current, TIF_RISCV_V_DEFER_RESTORE); #endif +#ifdef CONFIG_RISCV_ISA_SUPM + if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) + envcfg_update_bits(current, ENVCFG_PMM, ENVCFG_PMM_PMLEN_0); +#endif } =20 void arch_release_task_struct(struct task_struct *tsk) @@ -242,3 +247,89 @@ void __init arch_task_cache_init(void) { riscv_v_setup_ctx_cache(); } + +#ifdef CONFIG_RISCV_ISA_SUPM +enum { + PMLEN_0 =3D 0, + PMLEN_7 =3D 7, + PMLEN_16 =3D 16, +}; + +static bool have_user_pmlen_7; +static bool have_user_pmlen_16; + +long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg) +{ + unsigned long valid_mask =3D PR_PMLEN_MASK; + struct thread_info *ti =3D task_thread_info(task); + unsigned long pmm; + u8 pmlen; + + if (is_compat_thread(ti)) + return -EINVAL; + + if (arg & ~valid_mask) + return -EINVAL; + + /* + * Prefer the smallest PMLEN that satisfies the user's request, + * in case choosing a larger PMLEN has a performance impact. + */ + pmlen =3D FIELD_GET(PR_PMLEN_MASK, arg); + if (pmlen =3D=3D PMLEN_0) + pmm =3D ENVCFG_PMM_PMLEN_0; + else if (pmlen <=3D PMLEN_7 && have_user_pmlen_7) + pmm =3D ENVCFG_PMM_PMLEN_7; + else if (pmlen <=3D PMLEN_16 && have_user_pmlen_16) + pmm =3D ENVCFG_PMM_PMLEN_16; + else + return -EINVAL; + + envcfg_update_bits(task, ENVCFG_PMM, pmm); + + return 0; +} + +long get_tagged_addr_ctrl(struct task_struct *task) +{ + struct thread_info *ti =3D task_thread_info(task); + long ret =3D 0; + + if (is_compat_thread(ti)) + return -EINVAL; + + switch (task->thread.envcfg & ENVCFG_PMM) { + case ENVCFG_PMM_PMLEN_7: + ret =3D FIELD_PREP(PR_PMLEN_MASK, PMLEN_7); + break; + case ENVCFG_PMM_PMLEN_16: + ret =3D FIELD_PREP(PR_PMLEN_MASK, PMLEN_16); + break; + } + + return ret; +} + +static bool try_to_set_pmm(unsigned long value) +{ + csr_set(CSR_ENVCFG, value); + return (csr_read_clear(CSR_ENVCFG, ENVCFG_PMM) & ENVCFG_PMM) =3D=3D value; +} + +static int __init tagged_addr_init(void) +{ + if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SUPM)) + return 0; + + /* + * envcfg.PMM is a WARL field. Detect which values are supported. + * Assume the supported PMLEN values are the same on all harts. + */ + csr_clear(CSR_ENVCFG, ENVCFG_PMM); + have_user_pmlen_7 =3D try_to_set_pmm(ENVCFG_PMM_PMLEN_7); + have_user_pmlen_16 =3D try_to_set_pmm(ENVCFG_PMM_PMLEN_16); + + return 0; +} +core_initcall(tagged_addr_init); +#endif /* CONFIG_RISCV_ISA_SUPM */ diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 35791791a879..cefd656ebf43 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -230,7 +230,7 @@ struct prctl_mm_map { # define PR_PAC_APDBKEY (1UL << 3) # define PR_PAC_APGAKEY (1UL << 4) =20 -/* Tagged user address controls for arm64 */ +/* Tagged user address controls for arm64 and RISC-V */ #define PR_SET_TAGGED_ADDR_CTRL 55 #define PR_GET_TAGGED_ADDR_CTRL 56 # define PR_TAGGED_ADDR_ENABLE (1UL << 0) @@ -244,6 +244,9 @@ struct prctl_mm_map { # define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT) /* Unused; kept only for source compatibility */ # define PR_MTE_TCF_SHIFT 1 +/* RISC-V pointer masking tag length */ +# define PR_PMLEN_SHIFT 24 +# define PR_PMLEN_MASK (0x7fUL << PR_PMLEN_SHIFT) =20 /* Control reclaim behavior when allocating memory */ #define PR_SET_IO_FLUSHER 57 --=20 2.45.1