-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
Showing
10 changed files
with
1,231 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 = *(®s->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; | ||
|
||
*(®s->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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 */ |
Oops, something went wrong.