Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/toolkit/themes/linux/mozapps/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 317 B image not shown  

Quelle  vector.c   Sprache: unbekannt

 
// 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);

Messung V0.5 in Prozent
C=94 H=90 G=91

[Dauer der Verarbeitung: 0.16 Sekunden, vorverarbeitet 2026-06-07]