@@ -8,6 +8,23 @@
#include <asm/ptrace.h>
+/* The Magic number for signal context frame header. */
+#define RVV_MAGIC 0x53465457
+#define END_MAGIC 0x0
+
+/* The size of END signal context header. */
+#define END_HDR_SIZE 0x0
+
+struct __riscv_ctx_hdr {
+ __u32 magic;
+ __u32 size;
+};
+
+struct __sc_riscv_v_state {
+ struct __riscv_ctx_hdr head;
+ struct __riscv_v_state v_state;
+} __attribute__((aligned(16)));
+
/*
* Signal context structure
*
@@ -17,6 +34,13 @@
struct sigcontext {
struct user_regs_struct sc_regs;
union __riscv_fp_state sc_fpregs;
+ /*
+ * 4K + 128 reserved for vector state and future expansion.
+ * This space is enough to store the vector context whose VLENB
+ * is less or equal to 128.
+ * (The size of the vector context is 4144 byte as VLENB is 128)
+ */
+ __u8 __reserved[4224] __attribute__((__aligned__(16)));
};
#endif /* _UAPI_ASM_RISCV_SIGCONTEXT_H */
@@ -75,6 +75,8 @@ void asm_offsets(void)
OFFSET(TSK_STACK_CANARY, task_struct, stack_canary);
#endif
+ OFFSET(RISCV_V_STATE_MAGIC, __riscv_ctx_hdr, magic);
+ OFFSET(RISCV_V_STATE_SIZE, __riscv_ctx_hdr, size);
OFFSET(RISCV_V_STATE_VSTART, __riscv_v_state, vstart);
OFFSET(RISCV_V_STATE_VL, __riscv_v_state, vl);
OFFSET(RISCV_V_STATE_VTYPE, __riscv_v_state, vtype);
@@ -20,15 +20,16 @@
#include <asm/csr.h>
extern u32 __user_rt_sigreturn[2];
+static size_t rvv_sc_size;
#define DEBUG_SIG 0
struct rt_sigframe {
struct siginfo info;
- struct ucontext uc;
#ifndef CONFIG_MMU
u32 sigreturn_code[2];
#endif
+ struct ucontext uc;
};
#ifdef CONFIG_FPU
@@ -85,16 +86,155 @@ static long save_fp_state(struct pt_regs *regs,
#define restore_fp_state(task, regs) (0)
#endif
+#ifdef CONFIG_VECTOR
+static long restore_v_state(struct pt_regs *regs, void **sc_reserved_ptr)
+{
+ long err;
+ struct __sc_riscv_v_state __user *state = (struct __sc_riscv_v_state *)(*sc_reserved_ptr);
+ void *datap;
+ __u32 magic;
+ __u32 size;
+
+ /* Get magic number and check it. */
+ err = __get_user(magic, &state->head.magic);
+ err = __get_user(size, &state->head.size);
+ if (unlikely(err))
+ return err;
+
+ if (magic != RVV_MAGIC || size != rvv_sc_size)
+ return -EINVAL;
+
+ /* Copy everything of __sc_riscv_v_state except datap. */
+ err = __copy_from_user(¤t->thread.vstate, &state->v_state,
+ RISCV_V_STATE_DATAP);
+ if (unlikely(err))
+ return err;
+
+ /* Copy the pointer datap itself. */
+ err = __get_user(datap, &state->v_state.datap);
+ if (unlikely(err))
+ return err;
+
+
+ /* Copy the whole vector content from user space datap. */
+ err = __copy_from_user(current->thread.vstate.datap, datap, riscv_vsize);
+ if (unlikely(err))
+ return err;
+
+ vstate_restore(current, regs);
+
+ /* Move sc_reserved_ptr to point the next signal context frame. */
+ *sc_reserved_ptr += size;
+
+ return err;
+}
+
+static long save_v_state(struct pt_regs *regs, void **sc_reserved_free_ptr)
+{
+ /*
+ * Put __sc_riscv_v_state to the user's signal context space pointed
+ * by sc_reserved_free_ptr and the datap point the address right
+ * after __sc_riscv_v_state.
+ */
+ struct __sc_riscv_v_state __user *state = (struct __sc_riscv_v_state *)
+ (*sc_reserved_free_ptr);
+ void *datap = state + 1;
+ long err;
+
+ *sc_reserved_free_ptr += rvv_sc_size;
+
+ err = __put_user(RVV_MAGIC, &state->head.magic);
+ err = __put_user(rvv_sc_size, &state->head.size);
+
+ vstate_save(current, regs);
+ /* Copy everything of vstate but datap. */
+ err = __copy_to_user(&state->v_state, ¤t->thread.vstate,
+ RISCV_V_STATE_DATAP);
+ if (unlikely(err))
+ return err;
+
+ /* Copy the pointer datap itself. */
+ err = __put_user(datap, &state->v_state.datap);
+ if (unlikely(err))
+ return err;
+
+ /* Copy the whole vector content to user space datap. */
+ err = __copy_to_user(datap, current->thread.vstate.datap, riscv_vsize);
+
+ return err;
+}
+#else
+#define save_v_state(task, regs) (0)
+#define restore_v_state(task, regs) (0)
+#endif
+
static long restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc)
{
long err;
+ void *sc_reserved_ptr = sc->__reserved;
/* sc_regs is structured the same as the start of pt_regs */
err = __copy_from_user(regs, &sc->sc_regs, sizeof(sc->sc_regs));
/* Restore the floating-point state. */
if (has_fpu())
err |= restore_fp_state(regs, &sc->sc_fpregs);
+
+ while (1 && !err) {
+ __u32 magic, size;
+ struct __riscv_ctx_hdr *head = (struct __riscv_ctx_hdr *)sc_reserved_ptr;
+
+ err |= __get_user(magic, &head->magic);
+ err |= __get_user(size, &head->size);
+ if (err)
+ goto done;
+
+ switch (magic) {
+ case 0:
+ if (size)
+ goto invalid;
+ goto done;
+ case RVV_MAGIC:
+ if (!has_vector())
+ goto invalid;
+ if (size != rvv_sc_size)
+ goto invalid;
+ err |= restore_v_state(regs, &sc_reserved_ptr);
+ break;
+ default:
+ goto invalid;
+ }
+ }
+done:
return err;
+
+invalid:
+ return -EINVAL;
+}
+
+static size_t cal_rt_frame_size(void)
+{
+ struct rt_sigframe __user *frame;
+ static size_t frame_size;
+ size_t total_context_size = 0;
+ size_t sc_reserved_size = sizeof(frame->uc.uc_mcontext.__reserved);
+
+ if (frame_size)
+ goto done;
+
+ frame_size = sizeof(*frame);
+
+ if (has_vector())
+ total_context_size += rvv_sc_size;
+ /* Preserved a __riscv_ctx_hdr for END signal context header. */
+ total_context_size += sizeof(struct __riscv_ctx_hdr);
+
+ if (total_context_size > sc_reserved_size)
+ frame_size += (total_context_size - sc_reserved_size);
+
+ frame_size = round_up(frame_size, 16);
+done:
+ return frame_size;
+
}
SYSCALL_DEFINE0(rt_sigreturn)
@@ -103,13 +243,14 @@ SYSCALL_DEFINE0(rt_sigreturn)
struct rt_sigframe __user *frame;
struct task_struct *task;
sigset_t set;
+ size_t frame_size = cal_rt_frame_size();
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
frame = (struct rt_sigframe __user *)regs->sp;
- if (!access_ok(frame, sizeof(*frame)))
+ if (!access_ok(frame, frame_size))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
@@ -142,11 +283,20 @@ static long setup_sigcontext(struct rt_sigframe __user *frame,
{
struct sigcontext __user *sc = &frame->uc.uc_mcontext;
long err;
+ void *sc_reserved_free_ptr = sc->__reserved;
+
/* sc_regs is structured the same as the start of pt_regs */
err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
/* Save the floating-point state. */
if (has_fpu())
err |= save_fp_state(regs, &sc->sc_fpregs);
+ /* Save the vector state. */
+ if (has_vector())
+ err |= save_v_state(regs, &sc_reserved_free_ptr);
+
+ /* Put END __riscv_ctx_hdr at the end. */
+ err = __put_user(END_MAGIC, &((struct __riscv_ctx_hdr *)sc_reserved_free_ptr)->magic);
+ err = __put_user(END_HDR_SIZE, &((struct __riscv_ctx_hdr *)sc_reserved_free_ptr)->size);
return err;
}
@@ -178,9 +328,10 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
{
struct rt_sigframe __user *frame;
long err = 0;
+ size_t frame_size = cal_rt_frame_size();
- frame = get_sigframe(ksig, regs, sizeof(*frame));
- if (!access_ok(frame, sizeof(*frame)))
+ frame = get_sigframe(ksig, regs, frame_size);
+ if (!access_ok(frame, frame_size))
return -EFAULT;
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
@@ -326,3 +477,9 @@ asmlinkage __visible void do_notify_resume(struct pt_regs *regs,
if (thread_info_flags & _TIF_NOTIFY_RESUME)
resume_user_mode_work(regs);
}
+
+void init_rt_signal_env(void);
+void __init init_rt_signal_env(void)
+{
+ rvv_sc_size = sizeof(struct __sc_riscv_v_state) + riscv_vsize;
+}