mirror of
https://github.com/torvalds/linux.git
synced 2025-04-11 04:53:02 +00:00

* The PH1520 pinctrl and dwmac drivers are enabeled in defconfig. * A redundant AQRL barrier has been removed from the futex cmpxchg implementation. * Support for the T-Head vector extensions, which includes exposing these extensions to userspace on systems that implement them. * Some more page table information is now printed on die() and systems that cause PA overflows. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAmedHIoTHHBhbG1lckBk YWJiZWx0LmNvbQAKCRAuExnzX7sYievXD/4hdt8h+fMM0I9mmJS096YevRJONdfe Wk7D5q4PBwSHISHahuzfphieBhqPVnYkkEd7Vw6xRrLbUnhA41Fe0uvR52dx5UZd 3LwrDV/kjGTD59x6A2Zo9bSs/qPKJ2WHmHwHM21jY5tvcIB2Lo4dF8HT63OrwVNW DxsujLO0jUw+HEwXPsfmUAZJWOPZuUnatl/9CaLMLwQv5N7yiMuz5oYDzJXTLnNh m3Hv3CCtj1EeQPqDoWzz9nZvmAKOwcblSzz6OAy+xrRk1N0N3QFQPbIaRvkI9OVz +wPHQiyx4KZNeAe0csV0uLQRIiXZV8rkCz5UT65s3Bfy3vukvzz+1VBdNnCqiP8Q RpCTcYw62Cr6BWnvyTh+s9bhHb1ijG043nXd/Ty7ZRPCNLKHY6oL1CZ0pgqbTwPs D2U2ZTZFTc35mPrU6QMfbTiUVWCU2XagFhI27Dgj3xh9mkBOQCHwk2Mrzn7uS4iz xGNnrjRnKtuwBrvD68JzxCkEi8INFn2ifbVr44VZrOdTM7XtODGAYrBohQtV62kU 2L+q8DoHYis+0xFbR1wdrY1mRZoe45boUFgwnOpmoBr9ULe584sL+526y7IkkEHu /9hmLPtLg7nyoR/rO1j1Sfg4Eqdwg5HY1TKNfagJZAdu23EDRwrcW1PD0P6vtDv8 j4og8MmL7dTt3A== =HbAQ -----END PGP SIGNATURE----- Merge tag 'riscv-for-linus-6.14-mw1' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux Pull RISC-V updates from Palmer Dabbelt: - The PH1520 pinctrl and dwmac drivers are enabeled in defconfig - A redundant AQRL barrier has been removed from the futex cmpxchg implementation - Support for the T-Head vector extensions, which includes exposing these extensions to userspace on systems that implement them - Some more page table information is now printed on die() and systems that cause PA overflows * tag 'riscv-for-linus-6.14-mw1' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux: riscv: add a warning when physical memory address overflows riscv/mm/fault: add show_pte() before die() riscv: Add ghostwrite vulnerability selftests: riscv: Support xtheadvector in vector tests selftests: riscv: Fix vector tests riscv: hwprobe: Document thead vendor extensions and xtheadvector extension riscv: hwprobe: Add thead vendor extension probing riscv: vector: Support xtheadvector save/restore riscv: Add xtheadvector instruction definitions riscv: csr: Add CSR encodings for CSR_VXRM/CSR_VXSAT RISC-V: define the elements of the VCSR vector CSR riscv: vector: Use vlenb from DT for thead riscv: Add thead and xtheadvector as a vendor extension riscv: dts: allwinner: Add xtheadvector to the D1/D1s devicetree dt-bindings: cpus: add a thead vlen register length property dt-bindings: riscv: Add xtheadvector ISA extension description RISC-V: Mark riscv_v_init() as __init riscv: defconfig: drop RT_GROUP_SCHED=y riscv/futex: Optimize atomic cmpxchg riscv: defconfig: enable pinctrl and dwmac support for TH1520
327 lines
7.8 KiB
C
327 lines
7.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 2023 SiFive
|
|
* Author: Andy Chiu <andy.chiu@sifive.com>
|
|
*/
|
|
#include <linux/export.h>
|
|
#include <linux/sched/signal.h>
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/prctl.h>
|
|
|
|
#include <asm/thread_info.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/insn.h>
|
|
#include <asm/vector.h>
|
|
#include <asm/csr.h>
|
|
#include <asm/elf.h>
|
|
#include <asm/ptrace.h>
|
|
#include <asm/bug.h>
|
|
|
|
static bool riscv_v_implicit_uacc = IS_ENABLED(CONFIG_RISCV_ISA_V_DEFAULT_ENABLE);
|
|
static struct kmem_cache *riscv_v_user_cachep;
|
|
#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
|
|
static struct kmem_cache *riscv_v_kernel_cachep;
|
|
#endif
|
|
|
|
unsigned long riscv_v_vsize __read_mostly;
|
|
EXPORT_SYMBOL_GPL(riscv_v_vsize);
|
|
|
|
int riscv_v_setup_vsize(void)
|
|
{
|
|
unsigned long this_vsize;
|
|
|
|
/*
|
|
* There are 32 vector registers with vlenb length.
|
|
*
|
|
* If the thead,vlenb property was provided by the firmware, use that
|
|
* instead of probing the CSRs.
|
|
*/
|
|
if (thead_vlenb_of) {
|
|
riscv_v_vsize = thead_vlenb_of * 32;
|
|
return 0;
|
|
}
|
|
|
|
riscv_v_enable();
|
|
this_vsize = csr_read(CSR_VLENB) * 32;
|
|
riscv_v_disable();
|
|
|
|
if (!riscv_v_vsize) {
|
|
riscv_v_vsize = this_vsize;
|
|
return 0;
|
|
}
|
|
|
|
if (riscv_v_vsize != this_vsize) {
|
|
WARN(1, "RISCV_ISA_V only supports one vlenb on SMP systems");
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __init riscv_v_setup_ctx_cache(void)
|
|
{
|
|
if (!(has_vector() || has_xtheadvector()))
|
|
return;
|
|
|
|
riscv_v_user_cachep = kmem_cache_create_usercopy("riscv_vector_ctx",
|
|
riscv_v_vsize, 16, SLAB_PANIC,
|
|
0, riscv_v_vsize, NULL);
|
|
#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
|
|
riscv_v_kernel_cachep = kmem_cache_create("riscv_vector_kctx",
|
|
riscv_v_vsize, 16,
|
|
SLAB_PANIC, NULL);
|
|
#endif
|
|
}
|
|
|
|
bool insn_is_vector(u32 insn_buf)
|
|
{
|
|
u32 opcode = insn_buf & __INSN_OPCODE_MASK;
|
|
u32 width, csr;
|
|
|
|
/*
|
|
* All V-related instructions, including CSR operations are 4-Byte. So,
|
|
* do not handle if the instruction length is not 4-Byte.
|
|
*/
|
|
if (unlikely(GET_INSN_LENGTH(insn_buf) != 4))
|
|
return false;
|
|
|
|
switch (opcode) {
|
|
case RVV_OPCODE_VECTOR:
|
|
return true;
|
|
case RVV_OPCODE_VL:
|
|
case RVV_OPCODE_VS:
|
|
width = RVV_EXRACT_VL_VS_WIDTH(insn_buf);
|
|
if (width == RVV_VL_VS_WIDTH_8 || width == RVV_VL_VS_WIDTH_16 ||
|
|
width == RVV_VL_VS_WIDTH_32 || width == RVV_VL_VS_WIDTH_64)
|
|
return true;
|
|
|
|
break;
|
|
case RVG_OPCODE_SYSTEM:
|
|
csr = RVG_EXTRACT_SYSTEM_CSR(insn_buf);
|
|
if ((csr >= CSR_VSTART && csr <= CSR_VCSR) ||
|
|
(csr >= CSR_VL && csr <= CSR_VLENB))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static int riscv_v_thread_zalloc(struct kmem_cache *cache,
|
|
struct __riscv_v_ext_state *ctx)
|
|
{
|
|
void *datap;
|
|
|
|
datap = kmem_cache_zalloc(cache, GFP_KERNEL);
|
|
if (!datap)
|
|
return -ENOMEM;
|
|
|
|
ctx->datap = datap;
|
|
memset(ctx, 0, offsetof(struct __riscv_v_ext_state, datap));
|
|
return 0;
|
|
}
|
|
|
|
void riscv_v_thread_alloc(struct task_struct *tsk)
|
|
{
|
|
#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
|
|
riscv_v_thread_zalloc(riscv_v_kernel_cachep, &tsk->thread.kernel_vstate);
|
|
#endif
|
|
}
|
|
|
|
void riscv_v_thread_free(struct task_struct *tsk)
|
|
{
|
|
if (tsk->thread.vstate.datap)
|
|
kmem_cache_free(riscv_v_user_cachep, tsk->thread.vstate.datap);
|
|
#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
|
|
if (tsk->thread.kernel_vstate.datap)
|
|
kmem_cache_free(riscv_v_kernel_cachep, tsk->thread.kernel_vstate.datap);
|
|
#endif
|
|
}
|
|
|
|
#define VSTATE_CTRL_GET_CUR(x) ((x) & PR_RISCV_V_VSTATE_CTRL_CUR_MASK)
|
|
#define VSTATE_CTRL_GET_NEXT(x) (((x) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) >> 2)
|
|
#define VSTATE_CTRL_MAKE_NEXT(x) (((x) << 2) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK)
|
|
#define VSTATE_CTRL_GET_INHERIT(x) (!!((x) & PR_RISCV_V_VSTATE_CTRL_INHERIT))
|
|
static inline int riscv_v_ctrl_get_cur(struct task_struct *tsk)
|
|
{
|
|
return VSTATE_CTRL_GET_CUR(tsk->thread.vstate_ctrl);
|
|
}
|
|
|
|
static inline int riscv_v_ctrl_get_next(struct task_struct *tsk)
|
|
{
|
|
return VSTATE_CTRL_GET_NEXT(tsk->thread.vstate_ctrl);
|
|
}
|
|
|
|
static inline bool riscv_v_ctrl_test_inherit(struct task_struct *tsk)
|
|
{
|
|
return VSTATE_CTRL_GET_INHERIT(tsk->thread.vstate_ctrl);
|
|
}
|
|
|
|
static inline void riscv_v_ctrl_set(struct task_struct *tsk, int cur, int nxt,
|
|
bool inherit)
|
|
{
|
|
unsigned long ctrl;
|
|
|
|
ctrl = cur & PR_RISCV_V_VSTATE_CTRL_CUR_MASK;
|
|
ctrl |= VSTATE_CTRL_MAKE_NEXT(nxt);
|
|
if (inherit)
|
|
ctrl |= PR_RISCV_V_VSTATE_CTRL_INHERIT;
|
|
tsk->thread.vstate_ctrl &= ~PR_RISCV_V_VSTATE_CTRL_MASK;
|
|
tsk->thread.vstate_ctrl |= ctrl;
|
|
}
|
|
|
|
bool riscv_v_vstate_ctrl_user_allowed(void)
|
|
{
|
|
return riscv_v_ctrl_get_cur(current) == PR_RISCV_V_VSTATE_CTRL_ON;
|
|
}
|
|
EXPORT_SYMBOL_GPL(riscv_v_vstate_ctrl_user_allowed);
|
|
|
|
bool riscv_v_first_use_handler(struct pt_regs *regs)
|
|
{
|
|
u32 __user *epc = (u32 __user *)regs->epc;
|
|
u32 insn = (u32)regs->badaddr;
|
|
|
|
if (!(has_vector() || has_xtheadvector()))
|
|
return false;
|
|
|
|
/* Do not handle if V is not supported, or disabled */
|
|
if (!riscv_v_vstate_ctrl_user_allowed())
|
|
return false;
|
|
|
|
/* If V has been enabled then it is not the first-use trap */
|
|
if (riscv_v_vstate_query(regs))
|
|
return false;
|
|
|
|
/* Get the instruction */
|
|
if (!insn) {
|
|
if (__get_user(insn, epc))
|
|
return false;
|
|
}
|
|
|
|
/* Filter out non-V instructions */
|
|
if (!insn_is_vector(insn))
|
|
return false;
|
|
|
|
/* Sanity check. datap should be null by the time of the first-use trap */
|
|
WARN_ON(current->thread.vstate.datap);
|
|
|
|
/*
|
|
* Now we sure that this is a V instruction. And it executes in the
|
|
* context where VS has been off. So, try to allocate the user's V
|
|
* context and resume execution.
|
|
*/
|
|
if (riscv_v_thread_zalloc(riscv_v_user_cachep, ¤t->thread.vstate)) {
|
|
force_sig(SIGBUS);
|
|
return true;
|
|
}
|
|
riscv_v_vstate_on(regs);
|
|
riscv_v_vstate_set_restore(current, regs);
|
|
return true;
|
|
}
|
|
|
|
void riscv_v_vstate_ctrl_init(struct task_struct *tsk)
|
|
{
|
|
bool inherit;
|
|
int cur, next;
|
|
|
|
if (!(has_vector() || has_xtheadvector()))
|
|
return;
|
|
|
|
next = riscv_v_ctrl_get_next(tsk);
|
|
if (!next) {
|
|
if (READ_ONCE(riscv_v_implicit_uacc))
|
|
cur = PR_RISCV_V_VSTATE_CTRL_ON;
|
|
else
|
|
cur = PR_RISCV_V_VSTATE_CTRL_OFF;
|
|
} else {
|
|
cur = next;
|
|
}
|
|
/* Clear next mask if inherit-bit is not set */
|
|
inherit = riscv_v_ctrl_test_inherit(tsk);
|
|
if (!inherit)
|
|
next = PR_RISCV_V_VSTATE_CTRL_DEFAULT;
|
|
|
|
riscv_v_ctrl_set(tsk, cur, next, inherit);
|
|
}
|
|
|
|
long riscv_v_vstate_ctrl_get_current(void)
|
|
{
|
|
if (!(has_vector() || has_xtheadvector()))
|
|
return -EINVAL;
|
|
|
|
return current->thread.vstate_ctrl & PR_RISCV_V_VSTATE_CTRL_MASK;
|
|
}
|
|
|
|
long riscv_v_vstate_ctrl_set_current(unsigned long arg)
|
|
{
|
|
bool inherit;
|
|
int cur, next;
|
|
|
|
if (!(has_vector() || has_xtheadvector()))
|
|
return -EINVAL;
|
|
|
|
if (arg & ~PR_RISCV_V_VSTATE_CTRL_MASK)
|
|
return -EINVAL;
|
|
|
|
cur = VSTATE_CTRL_GET_CUR(arg);
|
|
switch (cur) {
|
|
case PR_RISCV_V_VSTATE_CTRL_OFF:
|
|
/* Do not allow user to turn off V if current is not off */
|
|
if (riscv_v_ctrl_get_cur(current) != PR_RISCV_V_VSTATE_CTRL_OFF)
|
|
return -EPERM;
|
|
|
|
break;
|
|
case PR_RISCV_V_VSTATE_CTRL_ON:
|
|
break;
|
|
case PR_RISCV_V_VSTATE_CTRL_DEFAULT:
|
|
cur = riscv_v_ctrl_get_cur(current);
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
next = VSTATE_CTRL_GET_NEXT(arg);
|
|
inherit = VSTATE_CTRL_GET_INHERIT(arg);
|
|
switch (next) {
|
|
case PR_RISCV_V_VSTATE_CTRL_DEFAULT:
|
|
case PR_RISCV_V_VSTATE_CTRL_OFF:
|
|
case PR_RISCV_V_VSTATE_CTRL_ON:
|
|
riscv_v_ctrl_set(current, cur, next, inherit);
|
|
return 0;
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
#ifdef CONFIG_SYSCTL
|
|
|
|
static const struct ctl_table riscv_v_default_vstate_table[] = {
|
|
{
|
|
.procname = "riscv_v_default_allow",
|
|
.data = &riscv_v_implicit_uacc,
|
|
.maxlen = sizeof(riscv_v_implicit_uacc),
|
|
.mode = 0644,
|
|
.proc_handler = proc_dobool,
|
|
},
|
|
};
|
|
|
|
static int __init riscv_v_sysctl_init(void)
|
|
{
|
|
if (has_vector() || has_xtheadvector())
|
|
if (!register_sysctl("abi", riscv_v_default_vstate_table))
|
|
return -EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
#else /* ! CONFIG_SYSCTL */
|
|
static int __init riscv_v_sysctl_init(void) { return 0; }
|
|
#endif /* ! CONFIG_SYSCTL */
|
|
|
|
static int __init riscv_v_init(void)
|
|
{
|
|
return riscv_v_sysctl_init();
|
|
}
|
|
core_initcall(riscv_v_init);
|