diff options
Diffstat (limited to 'arch/openrisc/kernel')
-rw-r--r-- | arch/openrisc/kernel/Makefile.syscalls | 3 | ||||
-rw-r--r-- | arch/openrisc/kernel/entry.S | 15 | ||||
-rw-r--r-- | arch/openrisc/kernel/module.c | 18 | ||||
-rw-r--r-- | arch/openrisc/kernel/process.c | 13 | ||||
-rw-r--r-- | arch/openrisc/kernel/ptrace.c | 18 | ||||
-rw-r--r-- | arch/openrisc/kernel/signal.c | 36 | ||||
-rw-r--r-- | arch/openrisc/kernel/sys_call_table.c | 9 | ||||
-rw-r--r-- | arch/openrisc/kernel/traps.c | 144 |
8 files changed, 154 insertions, 102 deletions
diff --git a/arch/openrisc/kernel/Makefile.syscalls b/arch/openrisc/kernel/Makefile.syscalls new file mode 100644 index 000000000000..525a1e7e7fc9 --- /dev/null +++ b/arch/openrisc/kernel/Makefile.syscalls @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +syscall_abis_32 += or1k time32 stat64 rlimit renameat diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index c9f48e750b72..440711d7bf40 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S @@ -106,8 +106,6 @@ 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) ;\ @@ -177,8 +175,6 @@ handler: ;\ /* r30 already save */ ;\ 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 @@ -219,8 +215,6 @@ handler: ;\ /* 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 ;\ @@ -852,6 +846,7 @@ _syscall_badsys: 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 */ @@ -1100,10 +1095,6 @@ 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 @@ -1126,10 +1117,6 @@ 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. */ diff --git a/arch/openrisc/kernel/module.c b/arch/openrisc/kernel/module.c index 532013f523ac..c9ff4c4a0b29 100644 --- a/arch/openrisc/kernel/module.c +++ b/arch/openrisc/kernel/module.c @@ -39,22 +39,32 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, value = sym->st_value + rel[i].r_addend; switch (ELF32_R_TYPE(rel[i].r_info)) { - case R_OR32_32: + case R_OR1K_32: *location = value; break; - case R_OR32_CONST: + case R_OR1K_LO_16_IN_INSN: *((uint16_t *)location + 1) = value; break; - case R_OR32_CONSTH: + case R_OR1K_HI_16_IN_INSN: *((uint16_t *)location + 1) = value >> 16; break; - case R_OR32_JUMPTARG: + case R_OR1K_INSN_REL_26: value -= (uint32_t)location; value >>= 2; value &= 0x03ffffff; value |= *location & 0xfc000000; *location = value; break; + case R_OR1K_AHI16: + /* Adjust the operand to match with a signed LO16. */ + value += 0x8000; + *((uint16_t *)location + 1) = value >> 16; + break; + case R_OR1K_SLO16: + /* Split value lower 16-bits. */ + value = ((value & 0xf800) << 10) | (value & 0x7ff); + *location = (*location & ~0x3e007ff) | value; + break; default: pr_err("module %s: Unknown relocation: %u\n", me->name, ELF32_R_TYPE(rel[i].r_info)); diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c index 86e02929f3ac..eef99fee2110 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c @@ -36,6 +36,7 @@ #include <linux/reboot.h> #include <linux/uaccess.h> +#include <asm/fpu.h> #include <asm/io.h> #include <asm/processor.h> #include <asm/spr_defs.h> @@ -65,7 +66,7 @@ void machine_restart(char *cmd) } /* - * This is used if pm_power_off has not been set by a power management + * This is used if a sys-off handler was not set by a power management * driver, in this case we can assume we are on a simulator. On * OpenRISC simulators l.nop 1 will trigger the simulator exit. */ @@ -89,10 +90,8 @@ void machine_halt(void) void machine_power_off(void) { printk(KERN_INFO "*** MACHINE POWER OFF ***\n"); - if (pm_power_off != NULL) - pm_power_off(); - else - default_power_off(); + do_kernel_power_off(); + default_power_off(); } /* @@ -246,6 +245,8 @@ struct task_struct *__switch_to(struct task_struct *old, local_irq_save(flags); + save_fpu(current); + /* current_set is an array of saved current pointers * (one for each cpu). we need them at user->kernel transition, * while we save them at kernel->user transition @@ -258,6 +259,8 @@ struct task_struct *__switch_to(struct task_struct *old, current_thread_info_set[smp_processor_id()] = new_ti; last = (_switch(old_ti, new_ti))->task; + restore_fpu(current); + local_irq_restore(flags); return last; diff --git a/arch/openrisc/kernel/ptrace.c b/arch/openrisc/kernel/ptrace.c index 1eeac3b62e9d..5091b18eab4c 100644 --- a/arch/openrisc/kernel/ptrace.c +++ b/arch/openrisc/kernel/ptrace.c @@ -88,6 +88,7 @@ static int genregs_set(struct task_struct *target, return ret; } +#ifdef CONFIG_FPU /* * 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 @@ -97,9 +98,7 @@ 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); + return membuf_store(&to, target->thread.fpcsr); } static int fpregs_set(struct task_struct *target, @@ -107,21 +106,20 @@ static int fpregs_set(struct task_struct *target, 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; + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &target->thread.fpcsr, 0, 4); } +#endif /* * Define the register sets available on OpenRISC under Linux */ enum or1k_regset { REGSET_GENERAL, +#ifdef CONFIG_FPU REGSET_FPU, +#endif }; static const struct user_regset or1k_regsets[] = { @@ -133,6 +131,7 @@ static const struct user_regset or1k_regsets[] = { .regset_get = genregs_get, .set = genregs_set, }, +#ifdef CONFIG_FPU [REGSET_FPU] = { .core_note_type = NT_PRFPREG, .n = sizeof(struct __or1k_fpu_state) / sizeof(long), @@ -141,6 +140,7 @@ static const struct user_regset or1k_regsets[] = { .regset_get = fpregs_get, .set = fpregs_set, }, +#endif }; static const struct user_regset_view user_or1k_native_view = { diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c index e2f21a5d8ad9..c7ab42e2cb7a 100644 --- a/arch/openrisc/kernel/signal.c +++ b/arch/openrisc/kernel/signal.c @@ -23,6 +23,7 @@ #include <linux/stddef.h> #include <linux/resume_user_mode.h> +#include <asm/fpu.h> #include <asm/processor.h> #include <asm/syscall.h> #include <asm/ucontext.h> @@ -39,6 +40,37 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs); asmlinkage int do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall); +#ifdef CONFIG_FPU +static long restore_fp_state(struct sigcontext __user *sc) +{ + long err; + + err = __copy_from_user(¤t->thread.fpcsr, &sc->fpcsr, sizeof(unsigned long)); + if (unlikely(err)) + return err; + + /* Restore the FPU state */ + restore_fpu(current); + + return 0; +} + +static long save_fp_state(struct sigcontext __user *sc) +{ + long err; + + /* Sync the user FPU state so we can copy to sigcontext */ + save_fpu(current); + + err = __copy_to_user(&sc->fpcsr, ¤t->thread.fpcsr, sizeof(unsigned long)); + + return err; +} +#else +#define save_fp_state(sc) (0) +#define restore_fp_state(sc) (0) +#endif + static int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { @@ -55,7 +87,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->fpcsr, sizeof(unsigned long)); + err |= restore_fp_state(sc); /* make sure the SM-bit is cleared so user-mode cannot fool us */ regs->sr &= ~SPR_SR_SM; @@ -118,7 +150,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->fpcsr, ®s->fpcsr, sizeof(unsigned long)); + err |= save_fp_state(sc); return err; } diff --git a/arch/openrisc/kernel/sys_call_table.c b/arch/openrisc/kernel/sys_call_table.c index 3d18008310e4..b2f57e2538f7 100644 --- a/arch/openrisc/kernel/sys_call_table.c +++ b/arch/openrisc/kernel/sys_call_table.c @@ -16,9 +16,14 @@ #include <asm/syscalls.h> -#undef __SYSCALL #define __SYSCALL(nr, call) [nr] = (call), +#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native) + +#define sys_mmap2 sys_mmap_pgoff +#define sys_clone __sys_clone +#define sys_clone3 __sys_clone3 +#define sys_fork __sys_fork void *sys_call_table[__NR_syscalls] = { -#include <asm/unistd.h> +#include <asm/syscall_table_32.h> }; diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index 9370888c9a7e..c195be9cc9fc 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -31,6 +31,7 @@ #include <linux/uaccess.h> #include <asm/bug.h> +#include <asm/fpu.h> #include <asm/io.h> #include <asm/processor.h> #include <asm/unwinder.h> @@ -51,16 +52,16 @@ static void print_trace(void *data, unsigned long addr, int reliable) { const char *loglvl = data; - printk("%s[<%p>] %s%pS\n", loglvl, (void *) addr, reliable ? "" : "? ", - (void *) addr); + pr_info("%s[<%p>] %s%pS\n", loglvl, (void *) addr, reliable ? "" : "? ", + (void *) addr); } static void print_data(unsigned long base_addr, unsigned long word, int i) { if (i == 0) - printk("(%08lx:)\t%08lx", base_addr + (i * 4), word); + pr_info("(%08lx:)\t%08lx", base_addr + (i * 4), word); else - printk(" %08lx:\t%08lx", base_addr + (i * 4), word); + pr_info(" %08lx:\t%08lx", base_addr + (i * 4), word); } /* displays a short stack trace */ @@ -69,7 +70,7 @@ void show_stack(struct task_struct *task, unsigned long *esp, const char *loglvl if (esp == NULL) esp = (unsigned long *)&esp; - printk("%sCall trace:\n", loglvl); + pr_info("%sCall trace:\n", loglvl); unwind_stack((void *)loglvl, esp, print_trace); } @@ -83,57 +84,56 @@ void show_registers(struct pt_regs *regs) if (user_mode(regs)) in_kernel = 0; - printk("CPU #: %d\n" - " 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", - regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]); - printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n", - regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]); - printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n", - regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]); - printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n", - regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]); - printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n", - regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]); - printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n", - regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]); - printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n", - regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]); - printk(" RES: %08lx oGPR11: %08lx\n", - regs->gpr[11], regs->orig_gpr11); - - printk("Process %s (pid: %d, stackpage=%08lx)\n", - current->comm, current->pid, (unsigned long)current); + pr_info("CPU #: %d\n" + " PC: %08lx SR: %08lx SP: %08lx\n", + smp_processor_id(), regs->pc, regs->sr, regs->sp); + pr_info("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n", + 0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]); + pr_info("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n", + regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]); + pr_info("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n", + regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]); + pr_info("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n", + regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]); + pr_info("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n", + regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]); + pr_info("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n", + regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]); + pr_info("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n", + regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]); + pr_info("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n", + regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]); + pr_info(" RES: %08lx oGPR11: %08lx\n", + regs->gpr[11], regs->orig_gpr11); + + pr_info("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, (unsigned long)current); /* * When in-kernel, we also print out the stack and code at the * time of the fault.. */ if (in_kernel) { - printk("\nStack: "); + pr_info("\nStack: "); show_stack(NULL, (unsigned long *)esp, KERN_EMERG); if (esp < PAGE_OFFSET) goto bad_stack; - printk("\n"); + pr_info("\n"); for (i = -8; i < 24; i += 1) { unsigned long word; if (__get_user(word, &((unsigned long *)esp)[i])) { bad_stack: - printk(" Bad Stack value."); + pr_info(" Bad Stack value."); break; } print_data(esp, word, i); } - printk("\nCode: "); + pr_info("\nCode: "); if (regs->pc < PAGE_OFFSET) goto bad; @@ -142,14 +142,14 @@ bad_stack: if (__get_user(word, &((unsigned long *)regs->pc)[i])) { bad: - printk(" Bad PC value."); + pr_info(" Bad PC value."); break; } print_data(regs->pc, word, i); } } - printk("\n"); + pr_info("\n"); } /* This is normally the 'Oops' routine */ @@ -157,10 +157,10 @@ void __noreturn die(const char *str, struct pt_regs *regs, long err) { console_verbose(); - printk("\n%s#: %04lx\n", str, err & 0xffff); + pr_emerg("\n%s#: %04lx\n", str, err & 0xffff); show_registers(regs); #ifdef CONFIG_JUMP_UPON_UNHANDLED_EXCEPTION - printk("\n\nUNHANDLED_EXCEPTION: entering infinite loop\n"); + pr_emerg("\n\nUNHANDLED_EXCEPTION: entering infinite loop\n"); /* shut down interrupts */ local_irq_disable(); @@ -173,36 +173,51 @@ void __noreturn die(const char *str, struct pt_regs *regs, long err) asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector) { - printk("Unable to handle exception at EA =0x%x, vector 0x%x", - ea, vector); + pr_emerg("Unable to handle exception at EA =0x%x, vector 0x%x", + ea, 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); + if (user_mode(regs)) { + int code = FPE_FLTUNK; +#ifdef CONFIG_FPU + unsigned long fpcsr; + + save_fpu(current); + fpcsr = current->thread.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 */ + current->thread.fpcsr &= ~SPR_FPCSR_ALLF; + restore_fpu(current); +#endif + force_sig_fault(SIGFPE, code, (void __user *)regs->pc); + } else { + pr_emerg("KERNEL: Illegal fpe exception 0x%.8lx\n", regs->pc); + die("Die:", regs, SIGFPE); + } } asmlinkage void do_trap(struct pt_regs *regs, unsigned long address) { - force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); + if (user_mode(regs)) { + force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); + } else { + pr_emerg("KERNEL: Illegal trap exception 0x%.8lx\n", regs->pc); + die("Die:", regs, SIGILL); + } } asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) @@ -211,8 +226,7 @@ asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address) /* Send a SIGBUS */ force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)address); } else { - printk("KERNEL: Unaligned Access 0x%.8lx\n", address); - show_registers(regs); + pr_emerg("KERNEL: Unaligned Access 0x%.8lx\n", address); die("Die:", regs, address); } @@ -224,8 +238,7 @@ asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address) /* Send a SIGBUS */ force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address); } else { /* Kernel mode */ - printk("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address); - show_registers(regs); + pr_emerg("KERNEL: Bus error (SIGBUS) 0x%.8lx\n", address); die("Die:", regs, address); } } @@ -419,9 +432,8 @@ asmlinkage void do_illegal_instruction(struct pt_regs *regs, /* Send a SIGILL */ force_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)address); } else { /* Kernel mode */ - printk("KERNEL: Illegal instruction (SIGILL) 0x%.8lx\n", - address); - show_registers(regs); + pr_emerg("KERNEL: Illegal instruction (SIGILL) 0x%.8lx\n", + address); die("Die:", regs, address); } } |