Skip to content

Commit d75439d

Browse files
committed
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
2 parents 3f2a190 + c91b4a0 commit d75439d

10 files changed

Lines changed: 101 additions & 31 deletions

File tree

arch/openrisc/include/asm/ptrace.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ struct pt_regs {
5959
* -1 for all other exceptions.
6060
*/
6161
long orig_gpr11; /* For restarting system calls */
62-
long dummy; /* Cheap alignment fix */
62+
long fpcsr; /* Floating point control status register. */
6363
long dummy2; /* Cheap alignment fix */
6464
};
6565

@@ -115,6 +115,6 @@ static inline long regs_return_value(struct pt_regs *regs)
115115
#define PT_GPR31 124
116116
#define PT_PC 128
117117
#define PT_ORIG_GPR11 132
118-
#define PT_SYSCALLNO 136
118+
#define PT_FPCSR 136
119119

120120
#endif /* __ASM_OPENRISC_PTRACE_H */

arch/openrisc/include/uapi/asm/elf.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ typedef unsigned long elf_greg_t;
5353
#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
5454
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
5555

56-
/* A placeholder; OR32 does not have fp support yes, so no fp regs for now. */
57-
typedef unsigned long elf_fpregset_t;
56+
typedef struct __or1k_fpu_state elf_fpregset_t;
5857

5958
/* EM_OPENRISC is defined in linux/elf-em.h */
6059
#define EM_OR32 0x8472

arch/openrisc/include/uapi/asm/ptrace.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ struct user_regs_struct {
3030
unsigned long pc;
3131
unsigned long sr;
3232
};
33+
34+
struct __or1k_fpu_state {
35+
unsigned long fpcsr;
36+
};
3337
#endif
3438

3539

arch/openrisc/include/uapi/asm/sigcontext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
struct sigcontext {
3030
struct user_regs_struct regs; /* needs to be first */
31+
struct __or1k_fpu_state fpu;
3132
unsigned long oldmask;
3233
};
3334

arch/openrisc/kernel/entry.S

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@
106106
l.mtspr r0,r3,SPR_EPCR_BASE ;\
107107
l.lwz r3,PT_SR(r1) ;\
108108
l.mtspr r0,r3,SPR_ESR_BASE ;\
109+
l.lwz r3,PT_FPCSR(r1) ;\
110+
l.mtspr r0,r3,SPR_FPCSR ;\
109111
l.lwz r2,PT_GPR2(r1) ;\
110112
l.lwz r3,PT_GPR3(r1) ;\
111113
l.lwz r4,PT_GPR4(r1) ;\
@@ -173,9 +175,10 @@ handler: ;\
173175
l.sw PT_GPR28(r1),r28 ;\
174176
l.sw PT_GPR29(r1),r29 ;\
175177
/* r30 already save */ ;\
176-
/* l.sw PT_GPR30(r1),r30*/ ;\
177178
l.sw PT_GPR31(r1),r31 ;\
178179
TRACE_IRQS_OFF_ENTRY ;\
180+
l.mfspr r30,r0,SPR_FPCSR ;\
181+
l.sw PT_FPCSR(r1),r30 ;\
179182
/* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
180183
l.addi r30,r0,-1 ;\
181184
l.sw PT_ORIG_GPR11(r1),r30
@@ -211,12 +214,13 @@ handler: ;\
211214
l.sw PT_GPR27(r1),r27 ;\
212215
l.sw PT_GPR28(r1),r28 ;\
213216
l.sw PT_GPR29(r1),r29 ;\
214-
/* r31 already saved */ ;\
215-
l.sw PT_GPR30(r1),r30 ;\
216-
/* l.sw PT_GPR31(r1),r31 */ ;\
217+
/* r30 already saved */ ;\
218+
l.sw PT_GPR31(r1),r31 ;\
217219
/* Store -1 in orig_gpr11 for non-syscall exceptions */ ;\
218220
l.addi r30,r0,-1 ;\
219221
l.sw PT_ORIG_GPR11(r1),r30 ;\
222+
l.mfspr r30,r0,SPR_FPCSR ;\
223+
l.sw PT_FPCSR(r1),r30 ;\
220224
l.addi r3,r1,0 ;\
221225
/* r4 is exception EA */ ;\
222226
l.addi r5,r0,vector ;\
@@ -844,9 +848,16 @@ _syscall_badsys:
844848

845849
/******* END SYSCALL HANDLING *******/
846850

847-
/* ---[ 0xd00: Trap exception ]------------------------------------------ */
851+
/* ---[ 0xd00: Floating Point exception ]-------------------------------- */
848852

849-
UNHANDLED_EXCEPTION(_vector_0xd00,0xd00)
853+
EXCEPTION_ENTRY(_fpe_trap_handler)
854+
CLEAR_LWA_FLAG(r3)
855+
/* r4: EA of fault (set by EXCEPTION_HANDLE) */
856+
l.jal do_fpe_trap
857+
l.addi r3,r1,0 /* pt_regs */
858+
859+
l.j _ret_from_exception
860+
l.nop
850861

851862
/* ---[ 0xe00: Trap exception ]------------------------------------------ */
852863

@@ -1089,6 +1100,10 @@ ENTRY(_switch)
10891100
l.sw PT_GPR28(r1),r28
10901101
l.sw PT_GPR30(r1),r30
10911102

1103+
/* Store the old FPU state to new pt_regs */
1104+
l.mfspr r29,r0,SPR_FPCSR
1105+
l.sw PT_FPCSR(r1),r29
1106+
10921107
l.addi r11,r10,0 /* Save old 'current' to 'last' return value*/
10931108

10941109
/* We use thread_info->ksp for storing the address of the above
@@ -1111,6 +1126,10 @@ ENTRY(_switch)
11111126
l.lwz r29,PT_SP(r1)
11121127
l.sw TI_KSP(r10),r29
11131128

1129+
/* Restore the old value of FPCSR */
1130+
l.lwz r29,PT_FPCSR(r1)
1131+
l.mtspr r0,r29,SPR_FPCSR
1132+
11141133
/* ...and restore the registers, except r11 because the return value
11151134
* has already been set above.
11161135
*/

arch/openrisc/kernel/head.S

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,9 +424,9 @@ _dispatch_do_ipage_fault:
424424
.org 0xc00
425425
EXCEPTION_HANDLE(_sys_call_handler)
426426

427-
/* ---[ 0xd00: Trap exception ]------------------------------------------ */
427+
/* ---[ 0xd00: Floating point exception ]--------------------------------- */
428428
.org 0xd00
429-
UNHANDLED_EXCEPTION(_vector_0xd00)
429+
EXCEPTION_HANDLE(_fpe_trap_handler)
430430

431431
/* ---[ 0xe00: Trap exception ]------------------------------------------ */
432432
.org 0xe00

arch/openrisc/kernel/ptrace.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,40 @@ static int genregs_set(struct task_struct *target,
8484
return ret;
8585
}
8686

87+
/*
88+
* As OpenRISC shares GPRs and floating point registers we don't need to export
89+
* the floating point registers again. So here we only export the fpcsr special
90+
* purpose register.
91+
*/
92+
static int fpregs_get(struct task_struct *target,
93+
const struct user_regset *regset,
94+
struct membuf to)
95+
{
96+
const struct pt_regs *regs = task_pt_regs(target);
97+
98+
return membuf_store(&to, regs->fpcsr);
99+
}
100+
101+
static int fpregs_set(struct task_struct *target,
102+
const struct user_regset *regset,
103+
unsigned int pos, unsigned int count,
104+
const void *kbuf, const void __user *ubuf)
105+
{
106+
struct pt_regs *regs = task_pt_regs(target);
107+
int ret;
108+
109+
/* FPCSR */
110+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
111+
&regs->fpcsr, 0, 4);
112+
return ret;
113+
}
114+
87115
/*
88116
* Define the register sets available on OpenRISC under Linux
89117
*/
90118
enum or1k_regset {
91119
REGSET_GENERAL,
120+
REGSET_FPU,
92121
};
93122

94123
static const struct user_regset or1k_regsets[] = {
@@ -100,6 +129,14 @@ static const struct user_regset or1k_regsets[] = {
100129
.regset_get = genregs_get,
101130
.set = genregs_set,
102131
},
132+
[REGSET_FPU] = {
133+
.core_note_type = NT_PRFPREG,
134+
.n = sizeof(struct __or1k_fpu_state) / sizeof(long),
135+
.size = sizeof(long),
136+
.align = sizeof(long),
137+
.regset_get = fpregs_get,
138+
.set = fpregs_set,
139+
},
103140
};
104141

105142
static const struct user_regset_view user_or1k_native_view = {

arch/openrisc/kernel/setup.c

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -152,21 +152,6 @@ static void print_cpuinfo(void)
152152
printk(KERN_INFO "-- custom unit(s)\n");
153153
}
154154

155-
static struct device_node *setup_find_cpu_node(int cpu)
156-
{
157-
u32 hwid;
158-
struct device_node *cpun;
159-
160-
for_each_of_cpu_node(cpun) {
161-
if (of_property_read_u32(cpun, "reg", &hwid))
162-
continue;
163-
if (hwid == cpu)
164-
return cpun;
165-
}
166-
167-
return NULL;
168-
}
169-
170155
void __init setup_cpuinfo(void)
171156
{
172157
struct device_node *cpu;
@@ -175,7 +160,7 @@ void __init setup_cpuinfo(void)
175160
int cpu_id = smp_processor_id();
176161
struct cpuinfo_or1k *cpuinfo = &cpuinfo_or1k[cpu_id];
177162

178-
cpu = setup_find_cpu_node(cpu_id);
163+
cpu = of_get_cpu_node(cpu_id, NULL);
179164
if (!cpu)
180165
panic("Couldn't find CPU%d in device tree...\n", cpu_id);
181166

@@ -255,7 +240,7 @@ static inline unsigned long extract_value(unsigned long reg, unsigned long mask)
255240
void calibrate_delay(void)
256241
{
257242
const int *val;
258-
struct device_node *cpu = setup_find_cpu_node(smp_processor_id());
243+
struct device_node *cpu = of_get_cpu_node(smp_processor_id(), NULL);
259244

260245
val = of_get_property(cpu, "clock-frequency", NULL);
261246
if (!val)

arch/openrisc/kernel/signal.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ static int restore_sigcontext(struct pt_regs *regs,
5050
err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long));
5151
err |= __copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long));
5252
err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long));
53+
err |= __copy_from_user(&regs->fpcsr, &sc->fpu.fpcsr, sizeof(unsigned long));
5354

5455
/* make sure the SM-bit is cleared so user-mode cannot fool us */
5556
regs->sr &= ~SPR_SR_SM;
@@ -112,6 +113,7 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
112113
err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
113114
err |= __copy_to_user(&sc->regs.pc, &regs->pc, sizeof(unsigned long));
114115
err |= __copy_to_user(&sc->regs.sr, &regs->sr, sizeof(unsigned long));
116+
err |= __copy_to_user(&sc->fpu.fpcsr, &regs->fpcsr, sizeof(unsigned long));
115117

116118
return err;
117119
}

arch/openrisc/kernel/traps.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ void show_registers(struct pt_regs *regs)
7575
in_kernel = 0;
7676

7777
printk("CPU #: %d\n"
78-
" PC: %08lx SR: %08lx SP: %08lx\n",
79-
smp_processor_id(), regs->pc, regs->sr, regs->sp);
78+
" PC: %08lx SR: %08lx SP: %08lx FPCSR: %08lx\n",
79+
smp_processor_id(), regs->pc, regs->sr, regs->sp,
80+
regs->fpcsr);
8081
printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
8182
0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
8283
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)
242243
die("Oops", regs, 9);
243244
}
244245

246+
asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address)
247+
{
248+
int code = FPE_FLTUNK;
249+
unsigned long fpcsr = regs->fpcsr;
250+
251+
if (fpcsr & SPR_FPCSR_IVF)
252+
code = FPE_FLTINV;
253+
else if (fpcsr & SPR_FPCSR_OVF)
254+
code = FPE_FLTOVF;
255+
else if (fpcsr & SPR_FPCSR_UNF)
256+
code = FPE_FLTUND;
257+
else if (fpcsr & SPR_FPCSR_DZF)
258+
code = FPE_FLTDIV;
259+
else if (fpcsr & SPR_FPCSR_IXF)
260+
code = FPE_FLTRES;
261+
262+
/* Clear all flags */
263+
regs->fpcsr &= ~SPR_FPCSR_ALLF;
264+
265+
force_sig_fault(SIGFPE, code, (void __user *)regs->pc);
266+
}
267+
245268
asmlinkage void do_trap(struct pt_regs *regs, unsigned long address)
246269
{
247270
force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc);

0 commit comments

Comments
 (0)