OpenRISC update for 6.4
Two things for OpenRISC this cycle. - Small cleanup for device tree cpu iteration from Rob Herring - Add support for storing, restoring and accessing user space FPU state, to allow for libc to support the FPU on OpenRISC. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE2cRzVK74bBA6Je/xw7McLV5mJ+QFAmROv2cACgkQw7McLV5m J+Ty8Q//WZsiDE+KnKUO8LNfE13V9Ut1prMZqf3XDEXscN0H5koTmpbwz3k56Ssa evYfxwlJgKlPRoiAzo1t3MhhBRvayYTC7JFJGBNqvErjVBZsxAEL90fi5/Nk95Y9 O1BpriMFNz1U/R4H8nU43CEVxpYlim3saimUUvnOpH2VsSQqkb+icqaOX+/FIXe0 NE0BQ+31PN2Zg5ai9bHgxP5+yL0XnMglK/XxmvbTRh/OpWx5vCnszufsuZvBy6um lzQ/0qF5KrVZxLCP3M5tkyPRm4FONVeiJcfxDWlcVK62UFpAWbGo8iZpgZHpKwtj DGImziX7eyGo6dB910SsObsQ0CzrCbd6Sz90MyTEEmr08Tb9Cz//Ax6CTyatA3Cv wG8eiYFzlib8Vpyjv8LzVzqgyvQNCbGl1+LqGm60+K7irA//+ROrPb5POA7b+8XC wf24IGKb6sMR7Cwb6HdFev/NdNvBUs91ksP3b+ReP0Il76p71s1YNsdfo2DiKBwL tQYlDz3Pi5tbIatMAwMcoiasHxt1TTivZ7oaG6c2QCQOCfTOv8kg+I28RSD0Muuo 6AMvRMPIsOMKXebv7hd70FcPn8c9RIkxxfcBJKf5igHM6Szjy19U05giCbVtSRVI yA/R3Z9aI2qJvC8NjoRh9RNkJibq7nZfPuVm+o0UB+z4TgIJXE0= =N9eu -----END PGP SIGNATURE----- Merge tag 'for-linus' of https://github.com/openrisc/linux Pull OpenRISC updates from Stafford Horne: "Two things for OpenRISC this cycle: - Small cleanup for device tree cpu iteration from Rob Herring - Add support for storing, restoring and accessing user space FPU state, to allow for libc to support the FPU on OpenRISC" * tag 'for-linus' of https://github.com/openrisc/linux: openrisc: Add floating point regset openrisc: Support floating point user api openrisc: Support storing and restoring fpu state openrisc: Properly store r31 to pt_regs on unhandled exceptions openrisc: Use common of_get_cpu_node() instead of open-coding
This commit is contained in:
commit
d75439d64a
|
@ -59,7 +59,7 @@ struct pt_regs {
|
|||
* -1 for all other exceptions.
|
||||
*/
|
||||
long orig_gpr11; /* For restarting system calls */
|
||||
long dummy; /* Cheap alignment fix */
|
||||
long fpcsr; /* Floating point control status register. */
|
||||
long dummy2; /* Cheap alignment fix */
|
||||
};
|
||||
|
||||
|
@ -115,6 +115,6 @@ static inline long regs_return_value(struct pt_regs *regs)
|
|||
#define PT_GPR31 124
|
||||
#define PT_PC 128
|
||||
#define PT_ORIG_GPR11 132
|
||||
#define PT_SYSCALLNO 136
|
||||
#define PT_FPCSR 136
|
||||
|
||||
#endif /* __ASM_OPENRISC_PTRACE_H */
|
||||
|
|
|
@ -53,8 +53,7 @@ typedef unsigned long elf_greg_t;
|
|||
#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
|
||||
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
||||
|
||||
/* A placeholder; OR32 does not have fp support yes, so no fp regs for now. */
|
||||
typedef unsigned long elf_fpregset_t;
|
||||
typedef struct __or1k_fpu_state elf_fpregset_t;
|
||||
|
||||
/* EM_OPENRISC is defined in linux/elf-em.h */
|
||||
#define EM_OR32 0x8472
|
||||
|
|
|
@ -30,6 +30,10 @@ struct user_regs_struct {
|
|||
unsigned long pc;
|
||||
unsigned long sr;
|
||||
};
|
||||
|
||||
struct __or1k_fpu_state {
|
||||
unsigned long fpcsr;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
struct sigcontext {
|
||||
struct user_regs_struct regs; /* needs to be first */
|
||||
struct __or1k_fpu_state fpu;
|
||||
unsigned long oldmask;
|
||||
};
|
||||
|
||||
|
|
|
@ -106,6 +106,8 @@
|
|||
l.mtspr r0,r3,SPR_EPCR_BASE ;\
|
||||
l.lwz r3,PT_SR(r1) ;\
|
||||
l.mtspr r0,r3,SPR_ESR_BASE ;\
|
||||
l.lwz r3,PT_FPCSR(r1) ;\
|
||||
l.mtspr r0,r3,SPR_FPCSR ;\
|
||||
l.lwz r2,PT_GPR2(r1) ;\
|
||||
l.lwz r3,PT_GPR3(r1) ;\
|
||||
l.lwz r4,PT_GPR4(r1) ;\
|
||||
|
@ -173,9 +175,10 @@ handler: ;\
|
|||
l.sw PT_GPR28(r1),r28 ;\
|
||||
l.sw PT_GPR29(r1),r29 ;\
|
||||
/* r30 already save */ ;\
|
||||
/* l.sw PT_GPR30(r1),r30*/ ;\
|
||||
l.sw PT_GPR31(r1),r31 ;\
|
||||
TRACE_IRQS_OFF_ENTRY ;\
|
||||
l.mfspr r30,r0,SPR_FPCSR ;\
|
||||
l.sw PT_FPCSR(r1),r30 ;\
|
||||
/* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
|
||||
l.addi r30,r0,-1 ;\
|
||||
l.sw PT_ORIG_GPR11(r1),r30
|
||||
|
@ -211,12 +214,13 @@ handler: ;\
|
|||
l.sw PT_GPR27(r1),r27 ;\
|
||||
l.sw PT_GPR28(r1),r28 ;\
|
||||
l.sw PT_GPR29(r1),r29 ;\
|
||||
/* r31 already saved */ ;\
|
||||
l.sw PT_GPR30(r1),r30 ;\
|
||||
/* l.sw PT_GPR31(r1),r31 */ ;\
|
||||
/* r30 already saved */ ;\
|
||||
l.sw PT_GPR31(r1),r31 ;\
|
||||
/* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
|
||||
l.addi r30,r0,-1 ;\
|
||||
l.sw PT_ORIG_GPR11(r1),r30 ;\
|
||||
l.mfspr r30,r0,SPR_FPCSR ;\
|
||||
l.sw PT_FPCSR(r1),r30 ;\
|
||||
l.addi r3,r1,0 ;\
|
||||
/* r4 is exception EA */ ;\
|
||||
l.addi r5,r0,vector ;\
|
||||
|
@ -844,9 +848,16 @@ _syscall_badsys:
|
|||
|
||||
/******* END SYSCALL HANDLING *******/
|
||||
|
||||
/* ---[ 0xd00: Trap exception ]------------------------------------------ */
|
||||
/* ---[ 0xd00: Floating Point exception ]-------------------------------- */
|
||||
|
||||
UNHANDLED_EXCEPTION(_vector_0xd00,0xd00)
|
||||
EXCEPTION_ENTRY(_fpe_trap_handler)
|
||||
CLEAR_LWA_FLAG(r3)
|
||||
/* r4: EA of fault (set by EXCEPTION_HANDLE) */
|
||||
l.jal do_fpe_trap
|
||||
l.addi r3,r1,0 /* pt_regs */
|
||||
|
||||
l.j _ret_from_exception
|
||||
l.nop
|
||||
|
||||
/* ---[ 0xe00: Trap exception ]------------------------------------------ */
|
||||
|
||||
|
@ -1089,6 +1100,10 @@ ENTRY(_switch)
|
|||
l.sw PT_GPR28(r1),r28
|
||||
l.sw PT_GPR30(r1),r30
|
||||
|
||||
/* Store the old FPU state to new pt_regs */
|
||||
l.mfspr r29,r0,SPR_FPCSR
|
||||
l.sw PT_FPCSR(r1),r29
|
||||
|
||||
l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/
|
||||
|
||||
/* We use thread_info->ksp for storing the address of the above
|
||||
|
@ -1111,6 +1126,10 @@ ENTRY(_switch)
|
|||
l.lwz r29,PT_SP(r1)
|
||||
l.sw TI_KSP(r10),r29
|
||||
|
||||
/* Restore the old value of FPCSR */
|
||||
l.lwz r29,PT_FPCSR(r1)
|
||||
l.mtspr r0,r29,SPR_FPCSR
|
||||
|
||||
/* ...and restore the registers, except r11 because the return value
|
||||
* has already been set above.
|
||||
*/
|
||||
|
|
|
@ -424,9 +424,9 @@ _dispatch_do_ipage_fault:
|
|||
.org 0xc00
|
||||
EXCEPTION_HANDLE(_sys_call_handler)
|
||||
|
||||
/* ---[ 0xd00: Trap exception ]------------------------------------------ */
|
||||
/* ---[ 0xd00: Floating point exception ]--------------------------------- */
|
||||
.org 0xd00
|
||||
UNHANDLED_EXCEPTION(_vector_0xd00)
|
||||
EXCEPTION_HANDLE(_fpe_trap_handler)
|
||||
|
||||
/* ---[ 0xe00: Trap exception ]------------------------------------------ */
|
||||
.org 0xe00
|
||||
|
|
|
@ -84,11 +84,40 @@ static int genregs_set(struct task_struct *target,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* As OpenRISC shares GPRs and floating point registers we don't need to export
|
||||
* the floating point registers again. So here we only export the fpcsr special
|
||||
* purpose register.
|
||||
*/
|
||||
static int fpregs_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
struct membuf to)
|
||||
{
|
||||
const struct pt_regs *regs = task_pt_regs(target);
|
||||
|
||||
return membuf_store(&to, regs->fpcsr);
|
||||
}
|
||||
|
||||
static int fpregs_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(target);
|
||||
int ret;
|
||||
|
||||
/* FPCSR */
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
®s->fpcsr, 0, 4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the register sets available on OpenRISC under Linux
|
||||
*/
|
||||
enum or1k_regset {
|
||||
REGSET_GENERAL,
|
||||
REGSET_FPU,
|
||||
};
|
||||
|
||||
static const struct user_regset or1k_regsets[] = {
|
||||
|
@ -100,6 +129,14 @@ static const struct user_regset or1k_regsets[] = {
|
|||
.regset_get = genregs_get,
|
||||
.set = genregs_set,
|
||||
},
|
||||
[REGSET_FPU] = {
|
||||
.core_note_type = NT_PRFPREG,
|
||||
.n = sizeof(struct __or1k_fpu_state) / sizeof(long),
|
||||
.size = sizeof(long),
|
||||
.align = sizeof(long),
|
||||
.regset_get = fpregs_get,
|
||||
.set = fpregs_set,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_or1k_native_view = {
|
||||
|
|
|
@ -152,21 +152,6 @@ static void print_cpuinfo(void)
|
|||
printk(KERN_INFO "-- custom unit(s)\n");
|
||||
}
|
||||
|
||||
static struct device_node *setup_find_cpu_node(int cpu)
|
||||
{
|
||||
u32 hwid;
|
||||
struct device_node *cpun;
|
||||
|
||||
for_each_of_cpu_node(cpun) {
|
||||
if (of_property_read_u32(cpun, "reg", &hwid))
|
||||
continue;
|
||||
if (hwid == cpu)
|
||||
return cpun;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __init setup_cpuinfo(void)
|
||||
{
|
||||
struct device_node *cpu;
|
||||
|
@ -175,7 +160,7 @@ void __init setup_cpuinfo(void)
|
|||
int cpu_id = smp_processor_id();
|
||||
struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[cpu_id];
|
||||
|
||||
cpu = setup_find_cpu_node(cpu_id);
|
||||
cpu = of_get_cpu_node(cpu_id, NULL);
|
||||
if (!cpu)
|
||||
panic("Couldn't find CPU%d in device tree...\n", cpu_id);
|
||||
|
||||
|
@ -255,7 +240,7 @@ static inline unsigned long extract_value(unsigned long reg, unsigned long mask)
|
|||
void calibrate_delay(void)
|
||||
{
|
||||
const int *val;
|
||||
struct device_node *cpu = setup_find_cpu_node(smp_processor_id());
|
||||
struct device_node *cpu = of_get_cpu_node(smp_processor_id(), NULL);
|
||||
|
||||
val = of_get_property(cpu, "clock-frequency", NULL);
|
||||
if (!val)
|
||||
|
|
|
@ -50,6 +50,7 @@ static int restore_sigcontext(struct pt_regs *regs,
|
|||
err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long));
|
||||
err |= __copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long));
|
||||
err |= __copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long));
|
||||
err |= __copy_from_user(®s->fpcsr, &sc->fpu.fpcsr, sizeof(unsigned long));
|
||||
|
||||
/* make sure the SM-bit is cleared so user-mode cannot fool us */
|
||||
regs->sr &= ~SPR_SR_SM;
|
||||
|
@ -112,6 +113,7 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
|
|||
err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
|
||||
err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long));
|
||||
err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long));
|
||||
err |= __copy_to_user(&sc->fpu.fpcsr, ®s->fpcsr, sizeof(unsigned long));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -75,8 +75,9 @@ void show_registers(struct pt_regs *regs)
|
|||
in_kernel = 0;
|
||||
|
||||
printk("CPU #: %d\n"
|
||||
" PC: %08lx SR: %08lx SP: %08lx\n",
|
||||
smp_processor_id(), regs->pc, regs->sr, regs->sp);
|
||||
" PC: %08lx SR: %08lx SP: %08lx FPCSR: %08lx\n",
|
||||
smp_processor_id(), regs->pc, regs->sr, regs->sp,
|
||||
regs->fpcsr);
|
||||
printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
|
||||
0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
|
||||
printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n",
|
||||
|
@ -242,6 +243,28 @@ asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector)
|
|||
die("Oops", regs, 9);
|
||||
}
|
||||
|
||||
asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address)
|
||||
{
|
||||
int code = FPE_FLTUNK;
|
||||
unsigned long fpcsr = regs->fpcsr;
|
||||
|
||||
if (fpcsr & SPR_FPCSR_IVF)
|
||||
code = FPE_FLTINV;
|
||||
else if (fpcsr & SPR_FPCSR_OVF)
|
||||
code = FPE_FLTOVF;
|
||||
else if (fpcsr & SPR_FPCSR_UNF)
|
||||
code = FPE_FLTUND;
|
||||
else if (fpcsr & SPR_FPCSR_DZF)
|
||||
code = FPE_FLTDIV;
|
||||
else if (fpcsr & SPR_FPCSR_IXF)
|
||||
code = FPE_FLTRES;
|
||||
|
||||
/* Clear all flags */
|
||||
regs->fpcsr &= ~SPR_FPCSR_ALLF;
|
||||
|
||||
force_sig_fault(SIGFPE, code, (void __user *)regs->pc);
|
||||
}
|
||||
|
||||
asmlinkage void do_trap(struct pt_regs *regs, unsigned long address)
|
||||
{
|
||||
force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc);
|
||||
|
|
Loading…
Reference in New Issue