Skip to content

Commit

Permalink
csky: Process management and Signal
Browse files Browse the repository at this point in the history
This patch adds files related to task_switch, sigcontext, signal,
fpu context switch.

Signed-off-by: Guo Ren <ren_guo@c-sky.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Eric W. Biederman <ebiederm@xmission.com>
  • Loading branch information
Guo Ren committed Oct 25, 2018
1 parent 013de2d commit e9564df
Show file tree
Hide file tree
Showing 10 changed files with 1,231 additions and 0 deletions.
275 changes: 275 additions & 0 deletions arch/csky/abiv2/fpu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.

#include <linux/ptrace.h>
#include <linux/uaccess.h>
#include <abi/reg_ops.h>

#define MTCR_MASK 0xFC00FFE0
#define MFCR_MASK 0xFC00FFE0
#define MTCR_DIST 0xC0006420
#define MFCR_DIST 0xC0006020

void __init init_fpu(void)
{
mtcr("cr<1, 2>", 0);
}

/*
* fpu_libc_helper() is to help libc to excute:
* - mfcr %a, cr<1, 2>
* - mfcr %a, cr<2, 2>
* - mtcr %a, cr<1, 2>
* - mtcr %a, cr<2, 2>
*/
int fpu_libc_helper(struct pt_regs *regs)
{
int fault;
unsigned long instrptr, regx = 0;
unsigned long index = 0, tmp = 0;
unsigned long tinstr = 0;
u16 instr_hi, instr_low;

instrptr = instruction_pointer(regs);
if (instrptr & 1)
return 0;

fault = __get_user(instr_low, (u16 *)instrptr);
if (fault)
return 0;

fault = __get_user(instr_hi, (u16 *)(instrptr + 2));
if (fault)
return 0;

tinstr = instr_hi | ((unsigned long)instr_low << 16);

if (((tinstr >> 21) & 0x1F) != 2)
return 0;

if ((tinstr & MTCR_MASK) == MTCR_DIST) {
index = (tinstr >> 16) & 0x1F;
if (index > 13)
return 0;

tmp = tinstr & 0x1F;
if (tmp > 2)
return 0;

regx = *(&regs->a0 + index);

if (tmp == 1)
mtcr("cr<1, 2>", regx);
else if (tmp == 2)
mtcr("cr<2, 2>", regx);
else
return 0;

regs->pc += 4;
return 1;
}

if ((tinstr & MFCR_MASK) == MFCR_DIST) {
index = tinstr & 0x1F;
if (index > 13)
return 0;

tmp = ((tinstr >> 16) & 0x1F);
if (tmp > 2)
return 0;

if (tmp == 1)
regx = mfcr("cr<1, 2>");
else if (tmp == 2)
regx = mfcr("cr<2, 2>");
else
return 0;

*(&regs->a0 + index) = regx;

regs->pc += 4;
return 1;
}

return 0;
}

void fpu_fpe(struct pt_regs *regs)
{
int sig, code;
unsigned int fesr;

fesr = mfcr("cr<2, 2>");

sig = SIGFPE;
code = FPE_FLTUNK;

if (fesr & FPE_ILLE) {
sig = SIGILL;
code = ILL_ILLOPC;
} else if (fesr & FPE_IDC) {
sig = SIGILL;
code = ILL_ILLOPN;
} else if (fesr & FPE_FEC) {
sig = SIGFPE;
if (fesr & FPE_IOC)
code = FPE_FLTINV;
else if (fesr & FPE_DZC)
code = FPE_FLTDIV;
else if (fesr & FPE_UFC)
code = FPE_FLTUND;
else if (fesr & FPE_OFC)
code = FPE_FLTOVF;
else if (fesr & FPE_IXC)
code = FPE_FLTRES;
}

force_sig_fault(sig, code, (void __user *)regs->pc, current);
}

#define FMFVR_FPU_REGS(vrx, vry) \
"fmfvrl %0, "#vrx"\n" \
"fmfvrh %1, "#vrx"\n" \
"fmfvrl %2, "#vry"\n" \
"fmfvrh %3, "#vry"\n"

#define FMTVR_FPU_REGS(vrx, vry) \
"fmtvrl "#vrx", %0\n" \
"fmtvrh "#vrx", %1\n" \
"fmtvrl "#vry", %2\n" \
"fmtvrh "#vry", %3\n"

#define STW_FPU_REGS(a, b, c, d) \
"stw %0, (%4, "#a")\n" \
"stw %1, (%4, "#b")\n" \
"stw %2, (%4, "#c")\n" \
"stw %3, (%4, "#d")\n"

#define LDW_FPU_REGS(a, b, c, d) \
"ldw %0, (%4, "#a")\n" \
"ldw %1, (%4, "#b")\n" \
"ldw %2, (%4, "#c")\n" \
"ldw %3, (%4, "#d")\n"

void save_to_user_fp(struct user_fp *user_fp)
{
unsigned long flg;
unsigned long tmp1, tmp2;
unsigned long *fpregs;

local_irq_save(flg);

tmp1 = mfcr("cr<1, 2>");
tmp2 = mfcr("cr<2, 2>");

user_fp->fcr = tmp1;
user_fp->fesr = tmp2;

fpregs = &user_fp->vr[0];
#ifdef CONFIG_CPU_HAS_FPUV2
#ifdef CONFIG_CPU_HAS_VDSP
asm volatile(
"vstmu.32 vr0-vr3, (%0)\n"
"vstmu.32 vr4-vr7, (%0)\n"
"vstmu.32 vr8-vr11, (%0)\n"
"vstmu.32 vr12-vr15, (%0)\n"
"fstmu.64 vr16-vr31, (%0)\n"
: "+a"(fpregs)
::"memory");
#else
asm volatile(
"fstmu.64 vr0-vr31, (%0)\n"
: "+a"(fpregs)
::"memory");
#endif
#else
{
unsigned long tmp3, tmp4;

asm volatile(
FMFVR_FPU_REGS(vr0, vr1)
STW_FPU_REGS(0, 4, 16, 20)
FMFVR_FPU_REGS(vr2, vr3)
STW_FPU_REGS(32, 36, 48, 52)
FMFVR_FPU_REGS(vr4, vr5)
STW_FPU_REGS(64, 68, 80, 84)
FMFVR_FPU_REGS(vr6, vr7)
STW_FPU_REGS(96, 100, 112, 116)
"addi %4, 128\n"
FMFVR_FPU_REGS(vr8, vr9)
STW_FPU_REGS(0, 4, 16, 20)
FMFVR_FPU_REGS(vr10, vr11)
STW_FPU_REGS(32, 36, 48, 52)
FMFVR_FPU_REGS(vr12, vr13)
STW_FPU_REGS(64, 68, 80, 84)
FMFVR_FPU_REGS(vr14, vr15)
STW_FPU_REGS(96, 100, 112, 116)
: "=a"(tmp1), "=a"(tmp2), "=a"(tmp3),
"=a"(tmp4), "+a"(fpregs)
::"memory");
}
#endif

local_irq_restore(flg);
}

void restore_from_user_fp(struct user_fp *user_fp)
{
unsigned long flg;
unsigned long tmp1, tmp2;
unsigned long *fpregs;

local_irq_save(flg);

tmp1 = user_fp->fcr;
tmp2 = user_fp->fesr;

mtcr("cr<1, 2>", tmp1);
mtcr("cr<2, 2>", tmp2);

fpregs = &user_fp->vr[0];
#ifdef CONFIG_CPU_HAS_FPUV2
#ifdef CONFIG_CPU_HAS_VDSP
asm volatile(
"vldmu.32 vr0-vr3, (%0)\n"
"vldmu.32 vr4-vr7, (%0)\n"
"vldmu.32 vr8-vr11, (%0)\n"
"vldmu.32 vr12-vr15, (%0)\n"
"fldmu.64 vr16-vr31, (%0)\n"
: "+a"(fpregs)
::"memory");
#else
asm volatile(
"fldmu.64 vr0-vr31, (%0)\n"
: "+a"(fpregs)
::"memory");
#endif
#else
{
unsigned long tmp3, tmp4;

asm volatile(
LDW_FPU_REGS(0, 4, 16, 20)
FMTVR_FPU_REGS(vr0, vr1)
LDW_FPU_REGS(32, 36, 48, 52)
FMTVR_FPU_REGS(vr2, vr3)
LDW_FPU_REGS(64, 68, 80, 84)
FMTVR_FPU_REGS(vr4, vr5)
LDW_FPU_REGS(96, 100, 112, 116)
FMTVR_FPU_REGS(vr6, vr7)
"addi %4, 128\n"
LDW_FPU_REGS(0, 4, 16, 20)
FMTVR_FPU_REGS(vr8, vr9)
LDW_FPU_REGS(32, 36, 48, 52)
FMTVR_FPU_REGS(vr10, vr11)
LDW_FPU_REGS(64, 68, 80, 84)
FMTVR_FPU_REGS(vr12, vr13)
LDW_FPU_REGS(96, 100, 112, 116)
FMTVR_FPU_REGS(vr14, vr15)
: "=a"(tmp1), "=a"(tmp2), "=a"(tmp3),
"=a"(tmp4), "+a"(fpregs)
::"memory");
}
#endif
local_irq_restore(flg);
}
66 changes: 66 additions & 0 deletions arch/csky/abiv2/inc/abi/fpu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* SPDX-License-Identifier: GPL-2.0 */
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.

#ifndef __ASM_CSKY_FPU_H
#define __ASM_CSKY_FPU_H

#include <asm/sigcontext.h>
#include <asm/ptrace.h>

int fpu_libc_helper(struct pt_regs *regs);
void fpu_fpe(struct pt_regs *regs);
void __init init_fpu(void);

void save_to_user_fp(struct user_fp *user_fp);
void restore_from_user_fp(struct user_fp *user_fp);

/*
* Define the fesr bit for fpe handle.
*/
#define FPE_ILLE (1 << 16) /* Illegal instruction */
#define FPE_FEC (1 << 7) /* Input float-point arithmetic exception */
#define FPE_IDC (1 << 5) /* Input denormalized exception */
#define FPE_IXC (1 << 4) /* Inexact exception */
#define FPE_UFC (1 << 3) /* Underflow exception */
#define FPE_OFC (1 << 2) /* Overflow exception */
#define FPE_DZC (1 << 1) /* Divide by zero exception */
#define FPE_IOC (1 << 0) /* Invalid operation exception */
#define FPE_REGULAR_EXCEPTION (FPE_IXC | FPE_UFC | FPE_OFC | FPE_DZC | FPE_IOC)

#ifdef CONFIG_OPEN_FPU_IDE
#define IDE_STAT (1 << 5)
#else
#define IDE_STAT 0
#endif

#ifdef CONFIG_OPEN_FPU_IXE
#define IXE_STAT (1 << 4)
#else
#define IXE_STAT 0
#endif

#ifdef CONFIG_OPEN_FPU_UFE
#define UFE_STAT (1 << 3)
#else
#define UFE_STAT 0
#endif

#ifdef CONFIG_OPEN_FPU_OFE
#define OFE_STAT (1 << 2)
#else
#define OFE_STAT 0
#endif

#ifdef CONFIG_OPEN_FPU_DZE
#define DZE_STAT (1 << 1)
#else
#define DZE_STAT 0
#endif

#ifdef CONFIG_OPEN_FPU_IOE
#define IOE_STAT (1 << 0)
#else
#define IOE_STAT 0
#endif

#endif /* __ASM_CSKY_FPU_H */
Loading

0 comments on commit e9564df

Please sign in to comment.