From b59a9504cb93db7fae31e60760725d48652a1fc3 Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Sat, 4 Dec 2004 21:35:05 +0000 Subject: De-optimize and decomplicate the spurious interrupt handler. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/entry.S | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 5eb429137e0..5e9a4416868 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -128,28 +128,25 @@ FEXPORT(syscall_exit_work) /* * Common spurious interrupt handler. */ - .text - .align 5 LEAF(spurious_interrupt) /* * Someone tried to fool us by sending an interrupt but we * couldn't find a cause for it. */ + PTR_LA t1, irq_err_count #ifdef CONFIG_SMP - lui t1, %hi(irq_err_count) -1: ll t0, %lo(irq_err_count)(t1) +1: ll t0, (t1) addiu t0, 1 - sc t0, %lo(irq_err_count)(t1) + sc t0, (t1) #if R10000_LLSC_WAR beqzl t0, 1b #else beqz t0, 1b #endif #else - lui t1, %hi(irq_err_count) - lw t0, %lo(irq_err_count)(t1) + lw t0, (t1) addiu t0, 1 - sw t0, %lo(irq_err_count)(t1) + sw t0, (t1) #endif j ret_from_irq END(spurious_interrupt) -- cgit v1.2.3 From 69903d6500c73af8329a5fba7153b0d50748981c Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Wed, 8 Dec 2004 10:32:45 +0000 Subject: Fix typos and formatting. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/genex.S | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index e7f6c1b9080..e5021c758ef 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -82,7 +82,7 @@ NESTED(except_vec3_r4000, 0, sp) li k0, 14<<2 beq k1, k0, handle_vcei #ifdef CONFIG_64BIT - dsll k1, k1, 1 + dsll k1, k1, 1 #endif .set pop PTR_L k0, exception_handlers(k1) @@ -90,17 +90,17 @@ NESTED(except_vec3_r4000, 0, sp) /* * Big shit, we now may have two dirty primary cache lines for the same - * physical address. We can savely invalidate the line pointed to by + * physical address. We can safely invalidate the line pointed to by * c0_badvaddr because after return from this exception handler the * load / store will be re-executed. */ handle_vced: - DMFC0 k0, CP0_BADVADDR + MFC0 k0, CP0_BADVADDR li k1, -4 # Is this ... and k0, k1 # ... really needed? mtc0 zero, CP0_TAGLO - cache Index_Store_Tag_D,(k0) - cache Hit_Writeback_Inv_SD,(k0) + cache Index_Store_Tag_D, (k0) + cache Hit_Writeback_Inv_SD, (k0) #ifdef CONFIG_PROC_FS PTR_LA k0, vced_count lw k1, (k0) -- cgit v1.2.3 From c264852726dde251a0c09ec22f61a9be8b0db68b Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Fri, 10 Dec 2004 12:56:33 +0000 Subject: Remove unused arguments from preempt_{start,stop}/local_irq_{en,dis}able. Don't clobber the preloaded TI_FLAGS in a2 needlessly. Unexport local functions. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/entry.S | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 5e9a4416868..be0354a14e2 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -19,11 +19,11 @@ #include #ifdef CONFIG_PREEMPT - .macro preempt_stop reg=t0 + .macro preempt_stop .endm #else - .macro preempt_stop reg=t0 - local_irq_disable \reg + .macro preempt_stop + local_irq_disable .endm #define resume_kernel restore_all #endif @@ -37,17 +37,17 @@ FEXPORT(ret_from_irq) andi t0, t0, KU_USER beqz t0, resume_kernel -FEXPORT(resume_userspace) - local_irq_disable t0 # make sure we dont miss an +resume_userspace: + local_irq_disable # make sure we dont miss an # interrupt setting need_resched # between sampling and return LONG_L a2, TI_FLAGS($28) # current->work - andi a2, _TIF_WORK_MASK # (ignoring syscall_trace) - bnez a2, work_pending + andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) + bnez t0, work_pending j restore_all #ifdef CONFIG_PREEMPT -ENTRY(resume_kernel) +resume_kernel: lw t0, TI_PRE_COUNT($28) bnez t0, restore_all need_resched: @@ -59,10 +59,10 @@ need_resched: beqz t0, restore_all li t0, PREEMPT_ACTIVE sw t0, TI_PRE_COUNT($28) - local_irq_enable t0 + local_irq_enable jal schedule sw zero, TI_PRE_COUNT($28) - local_irq_disable t0 + local_irq_disable b need_resched #endif @@ -88,13 +88,13 @@ FEXPORT(restore_partial) # restore partial frame RESTORE_SP_AND_RET .set at -FEXPORT(work_pending) - andi t0, a2, _TIF_NEED_RESCHED +work_pending: + andi t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS beqz t0, work_notifysig work_resched: jal schedule - local_irq_disable t0 # make sure need_resched and + local_irq_disable # make sure need_resched and # signals dont change between # sampling and return LONG_L a2, TI_FLAGS($28) @@ -113,11 +113,10 @@ work_notifysig: # deal with pending signals and FEXPORT(syscall_exit_work_partial) SAVE_STATIC -FEXPORT(syscall_exit_work) - LONG_L t0, TI_FLAGS($28) - li t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT - and t0, t1 - beqz t0, work_pending # trace bit is set +syscall_exit_work: + li t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT + and t0, a2 # a2 is preloaded with TI_FLAGS + beqz t0, work_pending # trace bit set? local_irq_enable # could let do_syscall_trace() # call schedule() instead move a0, sp -- cgit v1.2.3 From 0964ce24d091a1d3dc7f667e1b107ab77d4325e6 Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Thu, 23 Dec 2004 08:21:39 +0000 Subject: Move the invalid pmd and pte tables from .data to .bss. Fix alignment. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/head.S | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 2a1b45d66f0..124c27e908f 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -200,19 +200,13 @@ NESTED(smp_bootstrap, 16, sp) .comm fw_arg2, SZREG, SZREG .comm fw_arg3, SZREG, SZREG - .macro page name, order=0 - .globl \name -\name: .size \name, (_PAGE_SIZE << \order) - .org . + (_PAGE_SIZE << \order) - .type \name, @object + .macro page name, order + .comm \name, (_PAGE_SIZE << \order), (_PAGE_SIZE << \order) .endm - .data - .align PAGE_SHIFT - /* - * ... but on 64-bit we've got three-level pagetables with a - * slightly different layout ... + * On 64-bit we've got three-level pagetables with a slightly + * different layout ... */ page swapper_pg_dir, _PGD_ORDER #ifdef CONFIG_64BIT -- cgit v1.2.3 From b188ffe876382ecc009ceb4fe033fd6ec7ba4ede Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 28 Dec 2004 07:49:43 +0000 Subject: Fix build with SMP disabled and preemption enabled. Signed-off-by: Ralf Baechle --- arch/mips/kernel/gdb-stub.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index d3fd1ab1427..7c46b336c7d 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -637,15 +637,18 @@ static struct gdb_bp_save async_bp; * and only one can be active at a time. */ extern spinlock_t smp_call_lock; + void set_async_breakpoint(unsigned long *epc) { /* skip breaking into userland */ if ((*epc & 0x80000000) == 0) return; +#ifdef CONFIG_SMP /* avoid deadlock if someone is make IPC */ if (spin_is_locked(&smp_call_lock)) return; +#endif async_bp.addr = *epc; *epc = (unsigned long)async_breakpoint; -- cgit v1.2.3 From 8c93650890a33318263880dec36603a6d5749b7e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 28 Dec 2004 09:09:19 +0000 Subject: Dummy ISA DMA functions for systems that don't have ISA but share drivers with ISA such as legacy free PCI. Signed-off-by: Ralf Baechle --- arch/mips/kernel/dma-no-isa.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 arch/mips/kernel/dma-no-isa.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/dma-no-isa.c b/arch/mips/kernel/dma-no-isa.c new file mode 100644 index 00000000000..6df8b07741e --- /dev/null +++ b/arch/mips/kernel/dma-no-isa.c @@ -0,0 +1,28 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004 by Ralf Baechle + * + * Dummy ISA DMA functions for systems that don't have ISA but share drivers + * with ISA such as legacy free PCI. + */ +#include +#include +#include + +DEFINE_SPINLOCK(dma_spin_lock); + +int request_dma(unsigned int dmanr, const char * device_id) +{ + return -EINVAL; +} + +void free_dma(unsigned int dmanr) +{ +} + +EXPORT_SYMBOL(dma_spin_lock); +EXPORT_SYMBOL(request_dma); +EXPORT_SYMBOL(free_dma); -- cgit v1.2.3 From c83cfc9c9477d0bc0e0a1ba29dfc58e0d42b2faf Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 21 Jun 2005 13:56:30 +0000 Subject: Get rid of early_init. There's more need to make this form of initialization actually useful and as is certainly unmergable with upstream. Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 28 ++-------------------------- arch/mips/kernel/vmlinux.lds.S | 6 ------ 2 files changed, 2 insertions(+), 32 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 12b531c295c..6fc51b29830 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -510,31 +510,7 @@ static inline void resource_init(void) #undef MAXMEM #undef MAXMEM_PFN -static int __initdata earlyinit_debug; - -static int __init earlyinit_debug_setup(char *str) -{ - earlyinit_debug = 1; - return 1; -} -__setup("earlyinit_debug", earlyinit_debug_setup); - -extern initcall_t __earlyinitcall_start, __earlyinitcall_end; - -static void __init do_earlyinitcalls(void) -{ - initcall_t *call, *start, *end; - - start = &__earlyinitcall_start; - end = &__earlyinitcall_end; - - for (call = start; call < end; call++) { - if (earlyinit_debug) - printk("calling earlyinitcall 0x%p\n", *call); - - (*call)(); - } -} +extern void plat_setup(void); void __init setup_arch(char **cmdline_p) { @@ -551,7 +527,7 @@ void __init setup_arch(char **cmdline_p) #endif /* call board setup routine */ - do_earlyinitcalls(); + plat_setup(); strlcpy(command_line, arcs_cmdline, sizeof(command_line)); strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index 482ac310c93..ff345f2c42c 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -96,12 +96,6 @@ SECTIONS .init.setup : { *(.init.setup) } __setup_end = .; - .early_initcall.init : { - __earlyinitcall_start = .; - *(.initcall.early1.init) - } - __earlyinitcall_end = .; - __initcall_start = .; .initcall.init : { *(.initcall1.init) -- cgit v1.2.3 From b053c98fbbe9942669af2f1a351eaeae1b344d38 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 26 Jan 2005 02:21:06 +0000 Subject: Fix register layout in o32 core dumps on 64-bit systems. Signed-off-by: Ralf Baechle --- arch/mips/kernel/binfmt_elfo32.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index b4075e99c45..3ef8c852e83 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -98,7 +98,7 @@ struct elf_prpsinfo32 #define init_elf_binfmt init_elf32_binfmt #define jiffies_to_timeval jiffies_to_compat_timeval -static __inline__ void +static inline void jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) { /* @@ -113,21 +113,26 @@ jiffies_to_compat_timeval(unsigned long jiffies, struct compat_timeval *value) #undef ELF_CORE_COPY_REGS #define ELF_CORE_COPY_REGS(_dest,_regs) elf32_core_copy_regs(_dest,_regs); -void elf32_core_copy_regs(elf_gregset_t _dest, struct pt_regs *_regs) +void elf32_core_copy_regs(elf_gregset_t grp, struct pt_regs *regs) { int i; - memset(_dest, 0, sizeof(elf_gregset_t)); - - /* XXXKW the 6 is from EF_REG0 in gdb/gdb/mips-linux-tdep.c, include/asm-mips/reg.h */ - for (i=6; i<38; i++) - _dest[i] = (elf_greg_t) _regs->regs[i-6]; - _dest[i++] = (elf_greg_t) _regs->lo; - _dest[i++] = (elf_greg_t) _regs->hi; - _dest[i++] = (elf_greg_t) _regs->cp0_epc; - _dest[i++] = (elf_greg_t) _regs->cp0_badvaddr; - _dest[i++] = (elf_greg_t) _regs->cp0_status; - _dest[i++] = (elf_greg_t) _regs->cp0_cause; + for (i = 0; i < EF_R0; i++) + grp[i] = 0; + grp[EF_R0] = 0; + for (i = 1; i <= 31; i++) + grp[EF_R0 + i] = (elf_greg_t) regs->regs[i]; + grp[EF_R26] = 0; + grp[EF_R27] = 0; + grp[EF_LO] = (elf_greg_t) regs->lo; + grp[EF_HI] = (elf_greg_t) regs->hi; + grp[EF_CP0_EPC] = (elf_greg_t) regs->cp0_epc; + grp[EF_CP0_BADVADDR] = (elf_greg_t) regs->cp0_badvaddr; + grp[EF_CP0_STATUS] = (elf_greg_t) regs->cp0_status; + grp[EF_CP0_CAUSE] = (elf_greg_t) regs->cp0_cause; +#ifdef EF_UNUSED0 + grp[EF_UNUSED0] = 0; +#endif } MODULE_DESCRIPTION("Binary format loader for compatibility with o32 Linux/MIPS binaries"); -- cgit v1.2.3 From c6237645d1e9e687031048f5ffd343133fddb55c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 26 Jan 2005 02:22:22 +0000 Subject: Signed-off-by: Ralf Baechle Fix TASK_SIZE for 32-bit processes on 64-bit kernels. --- arch/mips/kernel/binfmt_elfn32.c | 4 +++- arch/mips/kernel/binfmt_elfo32.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c index 6b645fbb1dd..d8e2674a154 100644 --- a/arch/mips/kernel/binfmt_elfn32.c +++ b/arch/mips/kernel/binfmt_elfn32.c @@ -52,7 +52,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #include #include -#include #include #include @@ -116,4 +115,7 @@ MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)"); #undef MODULE_DESCRIPTION #undef MODULE_AUTHOR +#undef TASK_SIZE +#define TASK_SIZE TASK_SIZE32 + #include "../../../fs/binfmt_elf.c" diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c index 3ef8c852e83..cec5f327e36 100644 --- a/arch/mips/kernel/binfmt_elfo32.c +++ b/arch/mips/kernel/binfmt_elfo32.c @@ -54,7 +54,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #include #include -#include #include #include @@ -141,4 +140,7 @@ MODULE_AUTHOR("Ralf Baechle (ralf@linux-mips.org)"); #undef MODULE_DESCRIPTION #undef MODULE_AUTHOR +#undef TASK_SIZE +#define TASK_SIZE TASK_SIZE32 + #include "../../../fs/binfmt_elf.c" -- cgit v1.2.3 From 925ddb04c5eee5668e7229c71580d458ed61eb9b Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 3 Feb 2005 23:06:29 +0000 Subject: Mask and ack CPU interrupts upon initialization. Keep the state of software interrupts when unmasking. Signed-off-by: Ralf Baechle --- arch/mips/kernel/irq_cpu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 2b936cf1ef7..8f8c15fa748 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -3,6 +3,8 @@ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * * Copyright (C) 2001 Ralf Baechle + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. + * Author: Maciej W. Rozycki * * This file define the irq handler for MIPS CPU interrupts. * @@ -37,7 +39,6 @@ static int mips_cpu_irq_base; static inline void unmask_mips_irq(unsigned int irq) { - clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); set_c0_status(0x100 << (irq - mips_cpu_irq_base)); } @@ -107,6 +108,10 @@ void __init mips_cpu_irq_init(int irq_base) { int i; + /* Mask interrupts. */ + clear_c0_status(ST0_IM); + clear_c0_cause(CAUSEF_IP); + for (i = irq_base; i < irq_base + 8; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; -- cgit v1.2.3 From a18815abcdfd9f10a6ce6fbec3ad1af1ae101ce7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 7 Feb 2005 02:54:29 +0000 Subject: Use preempt_schedule_irq. Signed-off-by: Ralf Baechle --- arch/mips/kernel/entry.S | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index be0354a14e2..ebc1a5d4f8b 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -48,6 +48,7 @@ resume_userspace: #ifdef CONFIG_PREEMPT resume_kernel: + local_irq_disable lw t0, TI_PRE_COUNT($28) bnez t0, restore_all need_resched: @@ -59,11 +60,7 @@ need_resched: beqz t0, restore_all li t0, PREEMPT_ACTIVE sw t0, TI_PRE_COUNT($28) - local_irq_enable - jal schedule - sw zero, TI_PRE_COUNT($28) - local_irq_disable - b need_resched + jal preempt_schedule_irq #endif FEXPORT(ret_from_fork) -- cgit v1.2.3 From 57f0060b8a2bb2a70a4cce1a37d5e0158cea92a6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 10 Feb 2005 12:00:06 +0000 Subject: Document why calling smp_call_function will deadlock when called with interrupts disabled. Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index af5cd3b8a39..1d3a4b50194 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -121,7 +121,19 @@ struct call_data_struct *call_data; * or are or have executed. * * You must not call this function with disabled interrupts or from a - * hardware interrupt handler or from a bottom half handler. + * hardware interrupt handler or from a bottom half handler: + * + * CPU A CPU B + * Disable interrupts + * smp_call_function() + * Take call_lock + * Send IPIs + * Wait for all cpus to acknowledge IPI + * CPU A has not responded, spin waiting + * for cpu A to respond, holding call_lock + * smp_call_function() + * Spin waiting for call_lock + * Deadlock Deadlock */ int smp_call_function (void (*func) (void *info), void *info, int retry, int wait) -- cgit v1.2.3 From b6e203d84da8298b903a0ebcad1a8170f3959b4f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 16 Feb 2005 21:18:52 +0000 Subject: Use generic compat_sys_wait4 to implement 32-bit wait4(2). Signed-off-by: Ralf Baechle --- arch/mips/kernel/linux32.c | 73 +----------------------------------------- arch/mips/kernel/scall64-n32.S | 2 +- arch/mips/kernel/scall64-o32.S | 2 +- 3 files changed, 3 insertions(+), 74 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index ece4564919d..dfb448c015e 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -215,81 +215,10 @@ sys32_readdir(unsigned int fd, void * dirent32, unsigned int count) return(n); } -struct rusage32 { - struct compat_timeval ru_utime; - struct compat_timeval ru_stime; - int ru_maxrss; - int ru_ixrss; - int ru_idrss; - int ru_isrss; - int ru_minflt; - int ru_majflt; - int ru_nswap; - int ru_inblock; - int ru_oublock; - int ru_msgsnd; - int ru_msgrcv; - int ru_nsignals; - int ru_nvcsw; - int ru_nivcsw; -}; - -static int -put_rusage (struct rusage32 *ru, struct rusage *r) -{ - int err; - - if (!access_ok(VERIFY_WRITE, ru, sizeof *ru)) - return -EFAULT; - - err = __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); - err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); - err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); - err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); - err |= __put_user (r->ru_maxrss, &ru->ru_maxrss); - err |= __put_user (r->ru_ixrss, &ru->ru_ixrss); - err |= __put_user (r->ru_idrss, &ru->ru_idrss); - err |= __put_user (r->ru_isrss, &ru->ru_isrss); - err |= __put_user (r->ru_minflt, &ru->ru_minflt); - err |= __put_user (r->ru_majflt, &ru->ru_majflt); - err |= __put_user (r->ru_nswap, &ru->ru_nswap); - err |= __put_user (r->ru_inblock, &ru->ru_inblock); - err |= __put_user (r->ru_oublock, &ru->ru_oublock); - err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd); - err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv); - err |= __put_user (r->ru_nsignals, &ru->ru_nsignals); - err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw); - err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw); - - return err; -} - -asmlinkage int -sys32_wait4(compat_pid_t pid, unsigned int * stat_addr, int options, - struct rusage32 * ru) -{ - if (!ru) - return sys_wait4(pid, stat_addr, options, NULL); - else { - struct rusage r; - int ret; - unsigned int status; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); - set_fs(old_fs); - if (put_rusage (ru, &r)) return -EFAULT; - if (stat_addr && put_user (status, stat_addr)) - return -EFAULT; - return ret; - } -} - asmlinkage int sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options) { - return sys32_wait4(pid, stat_addr, options, NULL); + return compat_sys_wait4(pid, stat_addr, options, NULL); } struct sysinfo32 { diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index e52049c87bc..3a56056d812 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -176,7 +176,7 @@ EXPORT(sysn32_call_table) PTR sys_fork PTR sys32_execve PTR sys_exit - PTR sys32_wait4 + PTR compat_sys_wait4 PTR sys_kill /* 6060 */ PTR sys32_newuname PTR sys_semget diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 739f3998d76..271b2cb14da 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -316,7 +316,7 @@ sys_call_table: PTR sys_vhangup PTR sys_ni_syscall /* was sys_idle */ PTR sys_ni_syscall /* sys_vm86 */ - PTR sys32_wait4 + PTR compat_sys_wait4 PTR sys_swapoff /* 4115 */ PTR sys32_sysinfo PTR sys32_ipc -- cgit v1.2.3 From a19050f301c55313826a649943d492c65f977479 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 16 Feb 2005 21:19:59 +0000 Subject: Waitid(2) now has 5 arguments. Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall32-o32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 17b5030fb6e..00e4a5ed1d8 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -618,7 +618,7 @@ einval: li v0, -EINVAL sys sys_mq_notify 2 /* 4275 */ sys sys_mq_getsetattr 3 sys sys_ni_syscall 0 /* sys_vserver */ - sys sys_waitid 4 + sys sys_waitid 5 sys sys_ni_syscall 0 /* available, was setaltroot */ sys sys_add_key 5 sys sys_request_key 4 -- cgit v1.2.3 From 54f2da755b7f0bf022ea204240cba824af4d80ad Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 16 Feb 2005 21:21:29 +0000 Subject: Implement 32-bit compatibility for waitid(2). Signed-off-by: Ralf Baechle --- arch/mips/kernel/linux32.c | 22 ++++++++++++++++++++++ arch/mips/kernel/scall64-n32.S | 2 +- arch/mips/kernel/scall64-o32.S | 2 +- arch/mips/kernel/signal32.c | 27 +++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index dfb448c015e..120dd897162 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -221,6 +221,28 @@ sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options) return compat_sys_wait4(pid, stat_addr, options, NULL); } +asmlinkage long +sysn32_waitid(int which, compat_pid_t pid, + siginfo_t __user *uinfo, int options, + struct compat_rusage __user *uru) +{ + struct rusage ru; + long ret; + mm_segment_t old_fs = get_fs(); + + set_fs (KERNEL_DS); + ret = sys_waitid(which, pid, uinfo, options, + uru ? (struct rusage __user *) &ru : NULL); + set_fs (old_fs); + + if (ret < 0 || uinfo->si_signo == 0) + return ret; + + if (uru) + ret = put_compat_rusage(&ru, uru); + return ret; +} + struct sysinfo32 { s32 uptime; u32 loads[3]; diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 3a56056d812..982248a1739 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -358,7 +358,7 @@ EXPORT(sysn32_call_table) PTR compat_sys_mq_notify PTR compat_sys_mq_getsetattr PTR sys_ni_syscall /* 6240, sys_vserver */ - PTR sys_waitid + PTR sysn32_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key PTR sys_request_key diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 271b2cb14da..00e0d2b8fd8 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -480,7 +480,7 @@ sys_call_table: PTR compat_sys_mq_notify /* 4275 */ PTR compat_sys_mq_getsetattr PTR sys_ni_syscall /* sys_vserver */ - PTR sys_waitid + PTR sys32_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key /* 4280 */ PTR sys_request_key diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 8ddfbd8d425..d50daee51fb 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -902,3 +902,30 @@ asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t *uinfo) set_fs (old_fs); return ret; } + +asmlinkage long +sys32_waitid(int which, compat_pid_t pid, + compat_siginfo_t __user *uinfo, int options, + struct compat_rusage __user *uru) +{ + siginfo_t info; + struct rusage ru; + long ret; + mm_segment_t old_fs = get_fs(); + + info.si_signo = 0; + set_fs (KERNEL_DS); + ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, + uru ? (struct rusage __user *) &ru : NULL); + set_fs (old_fs); + + if (ret < 0 || info.si_signo == 0) + return ret; + + if (uru && (ret = put_compat_rusage(&ru, uru))) + return ret; + + BUG_ON(info.si_code & __SI_MASK); + info.si_code |= __SI_CHLD; + return copy_siginfo_to_user32(uinfo, &info); +} -- cgit v1.2.3 From 09276d905ef7498212ef69d5c324d027dc405896 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 16 Feb 2005 21:22:40 +0000 Subject: 32-bit compatibility for ptrace GETEVENTMSG operation. Signed-off-by: Ralf Baechle --- arch/mips/kernel/ptrace32.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index eee207969c2..a8a72c9a1cc 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -273,6 +272,11 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) ret = ptrace_detach(child, data); break; + case PTRACE_GETEVENTMSG: + ret = put_user(child->ptrace_message, + (unsigned int __user *) (unsigned long) data); + break; + default: ret = ptrace_request(child, request, addr, data); break; -- cgit v1.2.3 From a982099ca5465dd848d8ae28a83a3e49ac7b612b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 16 Feb 2005 21:24:16 +0000 Subject: Update to match the native siginfo structure and code. Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal32.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index d50daee51fb..18c028ba9ef 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -76,8 +76,10 @@ typedef struct compat_siginfo { /* POSIX.1b timers */ struct { - unsigned int _timer1; - unsigned int _timer2; + timer_t _tid; /* timer id */ + int _overrun; /* overrun count */ + sigval_t32 _sigval; /* same as below */ + int _sys_private; /* not to be passed to user */ } _timer; /* POSIX.1b signals */ @@ -411,6 +413,11 @@ int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from) err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); else { switch (from->si_code >> 16) { + case __SI_TIMER >> 16: + err |= __put_user(from->si_tid, &to->si_tid); + err |= __put_user(from->si_overrun, &to->si_overrun); + err |= __put_user(from->si_int, &to->si_int); + break; case __SI_CHLD >> 16: err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_stime, &to->si_stime); -- cgit v1.2.3 From d1abb6a2b8b57fa14ae0f69d4a3cb07ff9cdb8d1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 16 Feb 2005 21:25:03 +0000 Subject: 32-bit compatibility for various timer-related system calls. Signed-off-by: Ralf Baechle --- arch/mips/kernel/linux32.c | 50 ++++++++++++++++++++++++++++++++++++++++++ arch/mips/kernel/scall64-n32.S | 18 +++++++-------- arch/mips/kernel/scall64-o32.S | 2 +- 3 files changed, 60 insertions(+), 10 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 120dd897162..e8e886dd52d 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -1418,3 +1418,53 @@ asmlinkage long sys32_socketcall(int call, unsigned int *args32) } return err; } + +struct sigevent32 { + u32 sigev_value; + u32 sigev_signo; + u32 sigev_notify; + u32 payload[(64 / 4) - 3]; +}; + +extern asmlinkage long +sys_timer_create(clockid_t which_clock, + struct sigevent __user *timer_event_spec, + timer_t __user * created_timer_id); + +long +sys32_timer_create(u32 clock, struct sigevent32 __user *se32, timer_t __user *timer_id) +{ + struct sigevent __user *p = NULL; + if (se32) { + struct sigevent se; + p = compat_alloc_user_space(sizeof(struct sigevent)); + memset(&se, 0, sizeof(struct sigevent)); + if (get_user(se.sigev_value.sival_int, &se32->sigev_value) || + __get_user(se.sigev_signo, &se32->sigev_signo) || + __get_user(se.sigev_notify, &se32->sigev_notify) || + __copy_from_user(&se._sigev_un._pad, &se32->payload, + sizeof(se32->payload)) || + copy_to_user(p, &se, sizeof(se))) + return -EFAULT; + } + return sys_timer_create(clock, p, timer_id); +} + +asmlinkage long +sysn32_rt_sigtimedwait(const sigset_t __user *uthese, + siginfo_t __user *uinfo, + const struct compat_timespec __user *uts32, + size_t sigsetsize) +{ + struct timespec __user *uts = NULL; + + if (uts32) { + struct timespec ts; + uts = compat_alloc_user_space(sizeof(struct timespec)); + if (get_user(ts.tv_sec, &uts32->tv_sec) || + get_user(ts.tv_nsec, &uts32->tv_nsec) || + copy_to_user (uts, &ts, sizeof (ts))) + return -EFAULT; + } + return sys_rt_sigtimedwait(uthese, uinfo, uts, sigsetsize); +} diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 982248a1739..e797f15bc0f 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -243,8 +243,8 @@ EXPORT(sysn32_call_table) PTR sys_capget PTR sys_capset PTR sys32_rt_sigpending /* 6125 */ - PTR compat_sys_rt_sigtimedwait - PTR sys32_rt_sigqueueinfo + PTR sysn32_rt_sigtimedwait + PTR sys_rt_sigqueueinfo PTR sys32_rt_sigsuspend PTR sys32_sigaltstack PTR compat_sys_utime /* 6130 */ @@ -337,15 +337,15 @@ EXPORT(sysn32_call_table) PTR compat_sys_statfs64 PTR compat_sys_fstatfs64 PTR sys_sendfile64 - PTR sys_timer_create /* 6220 */ - PTR sys_timer_settime - PTR sys_timer_gettime + PTR sys32_timer_create /* 6220 */ + PTR compat_sys_timer_settime + PTR compat_sys_timer_gettime PTR sys_timer_getoverrun PTR sys_timer_delete - PTR sys_clock_settime /* 6225 */ - PTR sys_clock_gettime - PTR sys_clock_getres - PTR sys_clock_nanosleep + PTR compat_sys_clock_settime /* 6225 */ + PTR compat_sys_clock_gettime + PTR compat_sys_clock_getres + PTR compat_sys_clock_nanosleep PTR sys_tgkill PTR compat_sys_utimes /* 6230 */ PTR sys_ni_syscall /* sys_mbind */ diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 00e0d2b8fd8..1017176bdce 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -459,7 +459,7 @@ sys_call_table: PTR sys_fadvise64_64 PTR compat_sys_statfs64 /* 4255 */ PTR compat_sys_fstatfs64 - PTR sys_timer_create + PTR sys32_timer_create PTR compat_sys_timer_settime PTR compat_sys_timer_gettime PTR sys_timer_getoverrun /* 4260 */ -- cgit v1.2.3 From 7ee8798f3756fc473e63abeba56fae3e192ce71f Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Sat, 19 Feb 2005 16:15:54 +0000 Subject: Until I figure out why NFS filesystems are having problems with the 'load_irix_binary' and having kernel faults, Irix support is disabled. I suspect locking of some sort, but I will now have to investigate further. Static IRIX binaries are now being detected properly and are using the ELF interpreter found in this file. Signed-off-by: Steven J. Hill Signed-off-by: Ralf Baechle --- arch/mips/kernel/irixelf.c | 226 ++++++++++++++++++++++++--------------------- 1 file changed, 123 insertions(+), 103 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 4af20cd91f9..881f125eecb 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -8,7 +8,7 @@ * * Copyright (C) 1993 - 1994 Eric Youngdale * Copyright (C) 1996 - 2004 David S. Miller - * Copyright (C) 2004 Steven J. Hill + * Copyright (C) 2004 - 2005 Steven J. Hill */ #include #include @@ -31,15 +31,16 @@ #include #include -#include #include +#include #include +#include #define DLINFO_ITEMS 12 #include -#undef DEBUG_ELF +#undef DEBUG static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_irix_library(struct file *); @@ -55,7 +56,7 @@ static struct linux_binfmt irix_format = { #define elf_addr_t unsigned long #endif -#ifdef DEBUG_ELF +#ifdef DEBUG /* Debugging routines. */ static char *get_elf_p_type(Elf32_Word p_type) { @@ -120,7 +121,7 @@ static void dump_phdrs(struct elf_phdr *ep, int pnum) print_phdr(i, ep); } } -#endif /* (DEBUG_ELF) */ +#endif /* DEBUG */ static void set_brk(unsigned long start, unsigned long end) { @@ -150,16 +151,16 @@ static void padzero(unsigned long elf_bss) } } -unsigned long * create_irix_tables(char * p, int argc, int envc, - struct elfhdr * exec, unsigned int load_addr, - unsigned int interp_load_addr, - struct pt_regs *regs, struct elf_phdr *ephdr) +static unsigned long * create_irix_tables(char * p, int argc, int envc, + struct elfhdr * exec, unsigned int load_addr, + unsigned int interp_load_addr, struct pt_regs *regs, + struct elf_phdr *ephdr) { elf_addr_t *argv; elf_addr_t *envp; elf_addr_t *sp, *csp; -#ifdef DEBUG_ELF +#ifdef DEBUG printk("create_irix_tables: p[%p] argc[%d] envc[%d] " "load_addr[%08x] interp_load_addr[%08x]\n", p, argc, envc, load_addr, interp_load_addr); @@ -248,14 +249,13 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, last_bss = 0; error = load_addr = 0; -#ifdef DEBUG_ELF +#ifdef DEBUG print_elfhdr(interp_elf_ex); #endif /* First of all, some simple consistency checks */ if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || - !irix_elf_check_arch(interp_elf_ex) || !interpreter->f_op->mmap) { printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type); return 0xffffffff; @@ -290,7 +290,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); -#ifdef DEBUG_ELF +#ifdef DEBUG dump_phdrs(elf_phdata, interp_elf_ex->e_phnum); #endif @@ -306,13 +306,11 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, elf_type |= MAP_FIXED; vaddr = eppnt->p_vaddr; -#ifdef DEBUG_ELF - printk("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", + pr_debug("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ", interpreter, vaddr, (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)), (unsigned long) elf_prot, (unsigned long) elf_type, (unsigned long) (eppnt->p_offset & 0xfffff000)); -#endif down_write(¤t->mm->mmap_sem); error = do_mmap(interpreter, vaddr, eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), @@ -324,14 +322,10 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, printk("Aieee IRIX interp mmap error=%d\n", error); break; /* Real error */ } -#ifdef DEBUG_ELF - printk("error=%08lx ", (unsigned long) error); -#endif + pr_debug("error=%08lx ", (unsigned long) error); if(!load_addr && interp_elf_ex->e_type == ET_DYN) { load_addr = error; -#ifdef DEBUG_ELF - printk("load_addr = error "); -#endif + pr_debug("load_addr = error "); } /* Find the end of the file mapping for this phdr, and keep @@ -345,17 +339,13 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, */ k = eppnt->p_memsz + eppnt->p_vaddr; if(k > last_bss) last_bss = k; -#ifdef DEBUG_ELF - printk("\n"); -#endif + pr_debug("\n"); } } /* Now use mmap to map the library into memory. */ if(error < 0 && error > -1024) { -#ifdef DEBUG_ELF - printk("got error %d\n", error); -#endif + pr_debug("got error %d\n", error); kfree(elf_phdata); return 0xffffffff; } @@ -365,16 +355,12 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex, * that there are zero-mapped pages up to and including the * last bss page. */ -#ifdef DEBUG_ELF - printk("padzero(%08lx) ", (unsigned long) (elf_bss)); -#endif + pr_debug("padzero(%08lx) ", (unsigned long) (elf_bss)); padzero(elf_bss); len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */ -#ifdef DEBUG_ELF - printk("last_bss[%08lx] len[%08lx]\n", (unsigned long) last_bss, - (unsigned long) len); -#endif + pr_debug("last_bss[%08lx] len[%08lx]\n", (unsigned long) last_bss, + (unsigned long) len); /* Map the last of the bss segment */ if (last_bss > len) { @@ -396,12 +382,7 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm) /* First of all, some simple consistency checks */ if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || - !irix_elf_check_arch(ehp) || !bprm->file->f_op->mmap) { - return -ENOEXEC; - } - - /* Only support MIPS ARCH2 or greater IRIX binaries for now. */ - if(!(ehp->e_flags & EF_MIPS_ARCH) && !(ehp->e_flags & 0x04)) { + !bprm->file->f_op->mmap) { return -ENOEXEC; } @@ -411,16 +392,17 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm) * XXX all registers as 64bits on cpu's capable of this at * XXX exception time plus frob the XTLB exception vector. */ - if((ehp->e_flags & 0x20)) { + if((ehp->e_flags & EF_MIPS_ABI2)) return -ENOEXEC; - } - return 0; /* It's ok. */ + return 0; } -#define IRIX_INTERP_PREFIX "/usr/gnemul/irix" - -/* Look for an IRIX ELF interpreter. */ +/* + * This is where the detailed check is performed. Irix binaries + * use interpreters with 'libc.so' in the name, so this function + * can differentiate between Linux and Irix binaries. + */ static inline int look_for_irix_interpreter(char **name, struct file **interpreter, struct elfhdr *interp_elf_ex, @@ -440,12 +422,13 @@ static inline int look_for_irix_interpreter(char **name, if (*name != NULL) goto out; - *name = kmalloc((epp->p_filesz + strlen(IRIX_INTERP_PREFIX)), - GFP_KERNEL); + *name = (char *) kmalloc((epp->p_filesz + + strlen(IRIX_EMUL)), + GFP_KERNEL); if (!*name) return -ENOMEM; - strcpy(*name, IRIX_INTERP_PREFIX); + strcpy(*name, IRIX_EMUL); retval = kernel_read(bprm->file, epp->p_offset, (*name + 16), epp->p_filesz); if (retval < 0) @@ -562,7 +545,7 @@ static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp, * process and the system, here we map the page and fill the * structure */ -void irix_map_prda_page (void) +static void irix_map_prda_page(void) { unsigned long v; struct prda *pp; @@ -601,14 +584,33 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) load_addr = 0; has_interp = has_ephdr = 0; - elf_ihdr = elf_ephdr = 0; + elf_ihdr = elf_ephdr = NULL; elf_ex = *((struct elfhdr *) bprm->buf); retval = -ENOEXEC; if (verify_binary(&elf_ex, bprm)) goto out; -#ifdef DEBUG_ELF + /* + * Telling -o32 static binaries from Linux and Irix apart from each + * other is difficult. There are 2 differences to be noted for static + * binaries from the 2 operating systems: + * + * 1) Irix binaries have their .text section before their .init + * section. Linux binaries are just the opposite. + * + * 2) Irix binaries usually have <= 12 sections and Linux + * binaries have > 20. + * + * We will use Method #2 since Method #1 would require us to read in + * the section headers which is way too much overhead. This appears + * to work for everything we have ran into so far. If anyone has a + * better method to tell the binaries apart, I'm listening. + */ + if (elf_ex.e_shnum > 20) + goto out; + +#ifdef DEBUG print_elfhdr(&elf_ex); #endif @@ -623,11 +625,10 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) } retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *)elf_phdata, size); - if (retval < 0) goto out_free_ph; -#ifdef DEBUG_ELF +#ifdef DEBUG dump_phdrs(elf_phdata, elf_ex.e_phnum); #endif @@ -644,9 +645,8 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) break; }; } -#ifdef DEBUG_ELF - printk("\n"); -#endif + + pr_debug("\n"); elf_bss = 0; elf_brk = 0; @@ -657,12 +657,19 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) end_code = 0; end_data = 0; - retval = look_for_irix_interpreter(&elf_interpreter, - &interpreter, + /* + * If we get a return value, we change the value to be ENOEXEC + * so that we can exit gracefully and the main binary format + * search loop in 'fs/exec.c' will move onto the next handler + * which should be the normal ELF binary handler. + */ + retval = look_for_irix_interpreter(&elf_interpreter, &interpreter, &interp_elf_ex, elf_phdata, bprm, elf_ex.e_phnum); - if (retval) + if (retval) { + retval = -ENOEXEC; goto out_free_file; + } if (elf_interpreter) { retval = verify_irix_interpreter(&interp_elf_ex); @@ -746,18 +753,16 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) * IRIX maps a page at 0x200000 which holds some system * information. Programs depend on this. */ - irix_map_prda_page (); + irix_map_prda_page(); padzero(elf_bss); -#ifdef DEBUG_ELF - printk("(start_brk) %lx\n" , (long) current->mm->start_brk); - printk("(end_code) %lx\n" , (long) current->mm->end_code); - printk("(start_code) %lx\n" , (long) current->mm->start_code); - printk("(end_data) %lx\n" , (long) current->mm->end_data); - printk("(start_stack) %lx\n" , (long) current->mm->start_stack); - printk("(brk) %lx\n" , (long) current->mm->brk); -#endif + pr_debug("(start_brk) %lx\n" , (long) current->mm->start_brk); + pr_debug("(end_code) %lx\n" , (long) current->mm->end_code); + pr_debug("(start_code) %lx\n" , (long) current->mm->start_code); + pr_debug("(end_data) %lx\n" , (long) current->mm->end_data); + pr_debug("(start_stack) %lx\n" , (long) current->mm->start_stack); + pr_debug("(brk) %lx\n" , (long) current->mm->brk); #if 0 /* XXX No fucking way dude... */ /* Why this, you ask??? Well SVr4 maps page 0 as read-only, @@ -782,8 +787,7 @@ out_free_dentry: allow_write_access(interpreter); fput(interpreter); out_free_interp: - if (elf_interpreter) - kfree(elf_interpreter); + kfree(elf_interpreter); out_free_file: out_free_ph: kfree (elf_phdata); @@ -813,7 +817,7 @@ static int load_irix_library(struct file *file) /* First of all, some simple consistency checks. */ if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || - !irix_elf_check_arch(&elf_ex) || !file->f_op->mmap) + !file->f_op->mmap) return -ENOEXEC; /* Now read in all of the header information. */ @@ -876,33 +880,34 @@ static int load_irix_library(struct file *file) */ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) { + unsigned long type, vaddr, filesz, offset, flags; struct elf_phdr *hp; struct file *filp; int i, retval; -#ifdef DEBUG_ELF - printk("irix_mapelf: fd[%d] user_phdrp[%p] cnt[%d]\n", - fd, user_phdrp, cnt); -#endif + pr_debug("irix_mapelf: fd[%d] user_phdrp[%p] cnt[%d]\n", + fd, user_phdrp, cnt); /* First get the verification out of the way. */ hp = user_phdrp; if (!access_ok(VERIFY_READ, hp, (sizeof(struct elf_phdr) * cnt))) { -#ifdef DEBUG_ELF - printk("irix_mapelf: access_ok fails!\n"); -#endif + pr_debug("irix_mapelf: bad pointer to ELF PHDR!\n"); + return -EFAULT; } -#ifdef DEBUG_ELF +#ifdef DEBUG dump_phdrs(user_phdrp, cnt); #endif - for(i = 0; i < cnt; i++, hp++) - if(hp->p_type != PT_LOAD) { + for (i = 0; i < cnt; i++, hp++) { + if (__get_user(type, &hp->p_type)) + return -EFAULT; + if (type != PT_LOAD) { printk("irix_mapelf: One section is not PT_LOAD!\n"); return -ENOEXEC; } + } filp = fget(fd); if (!filp) @@ -917,29 +922,40 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) for(i = 0; i < cnt; i++, hp++) { int prot; - prot = (hp->p_flags & PF_R) ? PROT_READ : 0; - prot |= (hp->p_flags & PF_W) ? PROT_WRITE : 0; - prot |= (hp->p_flags & PF_X) ? PROT_EXEC : 0; + retval = __get_user(vaddr, &hp->p_vaddr); + retval |= __get_user(filesz, &hp->p_filesz); + retval |= __get_user(offset, &hp->p_offset); + retval |= __get_user(flags, &hp->p_flags); + if (retval) + return retval; + + prot = (flags & PF_R) ? PROT_READ : 0; + prot |= (flags & PF_W) ? PROT_WRITE : 0; + prot |= (flags & PF_X) ? PROT_EXEC : 0; + down_write(¤t->mm->mmap_sem); - retval = do_mmap(filp, (hp->p_vaddr & 0xfffff000), - (hp->p_filesz + (hp->p_vaddr & 0xfff)), + retval = do_mmap(filp, (vaddr & 0xfffff000), + (filesz + (vaddr & 0xfff)), prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE), - (hp->p_offset & 0xfffff000)); + (offset & 0xfffff000)); up_write(¤t->mm->mmap_sem); - if(retval != (hp->p_vaddr & 0xfffff000)) { + if (retval != (vaddr & 0xfffff000)) { printk("irix_mapelf: do_mmap fails with %d!\n", retval); fput(filp); return retval; } } -#ifdef DEBUG_ELF - printk("irix_mapelf: Success, returning %08lx\n", - (unsigned long) user_phdrp->p_vaddr); -#endif + pr_debug("irix_mapelf: Success, returning %08lx\n", + (unsigned long) user_phdrp->p_vaddr); + fput(filp); - return user_phdrp->p_vaddr; + + if (__get_user(vaddr, &user_phdrp->p_vaddr)) + return -EFAULT; + + return vaddr; } /* @@ -954,7 +970,7 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) */ static int dump_write(struct file *file, const void *addr, int nr) { - return file->f_op->write(file, addr, nr, &file->f_pos) == nr; + return file->f_op->write(file, (const char *) addr, nr, &file->f_pos) == nr; } static int dump_seek(struct file *file, off_t off) @@ -1073,7 +1089,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) /* Count what's needed to dump, up to the limit of coredump size. */ segs = 0; size = 0; - for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { + for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { if (maydump(vma)) { int sz = vma->vm_end-vma->vm_start; @@ -1187,9 +1203,9 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) len = current->mm->arg_end - current->mm->arg_start; len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; - copy_from_user(&psinfo.pr_psargs, + (void *) copy_from_user(&psinfo.pr_psargs, (const char *)current->mm->arg_start, len); - for(i = 0; i < len; i++) + for (i = 0; i < len; i++) if (psinfo.pr_psargs[i] == 0) psinfo.pr_psargs[i] = ' '; psinfo.pr_psargs[len] = 0; @@ -1256,8 +1272,10 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) phdr.p_memsz = sz; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; - if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; - if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; + if (vma->vm_flags & VM_WRITE) + phdr.p_flags |= PF_W; + if (vma->vm_flags & VM_EXEC) + phdr.p_flags |= PF_X; phdr.p_align = PAGE_SIZE; DUMP_WRITE(&phdr, sizeof(phdr)); @@ -1299,7 +1317,7 @@ end_coredump: static int __init init_irix_binfmt(void) { - int init_inventory(void); + extern int init_inventory(void); extern asmlinkage unsigned long sys_call_table; extern asmlinkage unsigned long sys_call_table_irix5; @@ -1318,7 +1336,9 @@ static int __init init_irix_binfmt(void) static void __exit exit_irix_binfmt(void) { - /* Remove the IRIX ELF loaders. */ + /* + * Remove the Irix ELF loader. + */ unregister_binfmt(&irix_format); } -- cgit v1.2.3 From 4e6a05fe5f87efd58da16fbf61e1f6329575fcfd Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Mon, 21 Feb 2005 10:45:09 +0000 Subject: Improved modules loader, more robust and works on 64bit kernels. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 6 +- arch/mips/kernel/module-elf32.c | 250 ------------------------------ arch/mips/kernel/module-elf64.c | 274 -------------------------------- arch/mips/kernel/module.c | 336 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 337 insertions(+), 529 deletions(-) delete mode 100644 arch/mips/kernel/module-elf32.c delete mode 100644 arch/mips/kernel/module-elf64.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index d3303584fbd..d54964d52c8 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -11,11 +11,7 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ irix5sys.o sysirix.o -ifdef CONFIG_MODULES -obj-y += mips_ksyms.o module.o -obj-$(CONFIG_32BIT) += module-elf32.o -obj-$(CONFIG_64BIT) += module-elf64.o -endif +obj-$(CONFIG_MODULES) += mips_ksyms.o module.o obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o diff --git a/arch/mips/kernel/module-elf32.c b/arch/mips/kernel/module-elf32.c deleted file mode 100644 index ffd216d6d6d..00000000000 --- a/arch/mips/kernel/module-elf32.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Copyright (C) 2001 Rusty Russell. - * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org) - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include - -struct mips_hi16 { - struct mips_hi16 *next; - Elf32_Addr *addr; - Elf32_Addr value; -}; - -static struct mips_hi16 *mips_hi16_list; - -void *module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - return vmalloc(size); -} - - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ -} - -int module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod) -{ - return 0; -} - -static int apply_r_mips_none(struct module *me, uint32_t *location, - Elf32_Addr v) -{ - return 0; -} - -static int apply_r_mips_32(struct module *me, uint32_t *location, - Elf32_Addr v) -{ - *location += v; - - return 0; -} - -static int apply_r_mips_26(struct module *me, uint32_t *location, - Elf32_Addr v) -{ - if (v % 4) { - printk(KERN_ERR "module %s: dangerous relocation\n", me->name); - return -ENOEXEC; - } - - if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { - printk(KERN_ERR - "module %s: relocation overflow\n", - me->name); - return -ENOEXEC; - } - - *location = (*location & ~0x03ffffff) | - ((*location + (v >> 2)) & 0x03ffffff); - - return 0; -} - -static int apply_r_mips_hi16(struct module *me, uint32_t *location, - Elf32_Addr v) -{ - struct mips_hi16 *n; - - /* - * We cannot relocate this one now because we don't know the value of - * the carry we need to add. Save the information, and let LO16 do the - * actual relocation. - */ - n = kmalloc(sizeof *n, GFP_KERNEL); - if (!n) - return -ENOMEM; - - n->addr = location; - n->value = v; - n->next = mips_hi16_list; - mips_hi16_list = n; - - return 0; -} - -static int apply_r_mips_lo16(struct module *me, uint32_t *location, - Elf32_Addr v) -{ - unsigned long insnlo = *location; - Elf32_Addr val, vallo; - - /* Sign extend the addend we extract from the lo insn. */ - vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; - - if (mips_hi16_list != NULL) { - struct mips_hi16 *l; - - l = mips_hi16_list; - while (l != NULL) { - struct mips_hi16 *next; - unsigned long insn; - - /* - * The value for the HI16 had best be the same. - */ - if (v != l->value) - goto out_danger; - - /* - * Do the HI16 relocation. Note that we actually don't - * need to know anything about the LO16 itself, except - * where to find the low 16 bits of the addend needed - * by the LO16. - */ - insn = *l->addr; - val = ((insn & 0xffff) << 16) + vallo; - val += v; - - /* - * Account for the sign extension that will happen in - * the low bits. - */ - val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff; - - insn = (insn & ~0xffff) | val; - *l->addr = insn; - - next = l->next; - kfree(l); - l = next; - } - - mips_hi16_list = NULL; - } - - /* - * Ok, we're done with the HI16 relocs. Now deal with the LO16. - */ - val = v + vallo; - insnlo = (insnlo & ~0xffff) | (val & 0xffff); - *location = insnlo; - - return 0; - -out_danger: - printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name); - - return -ENOEXEC; -} - -static int (*reloc_handlers[]) (struct module *me, uint32_t *location, - Elf32_Addr v) = { - [R_MIPS_NONE] = apply_r_mips_none, - [R_MIPS_32] = apply_r_mips_32, - [R_MIPS_26] = apply_r_mips_26, - [R_MIPS_HI16] = apply_r_mips_hi16, - [R_MIPS_LO16] = apply_r_mips_lo16 -}; - -int apply_relocate(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr; - Elf32_Sym *sym; - uint32_t *location; - unsigned int i; - Elf32_Addr v; - int res; - - pr_debug("Applying relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); - - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { - Elf32_Word r_info = rel[i].r_info; - - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rel[i].r_offset; - /* This is the symbol it is referring to */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_addr - + ELF32_R_SYM(r_info); - if (!sym->st_value) { - printk(KERN_WARNING "%s: Unknown symbol %s\n", - me->name, strtab + sym->st_name); - return -ENOENT; - } - - v = sym->st_value; - - res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v); - if (res) - return res; - } - - return 0; -} - -int apply_relocate_add(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - /* - * Current binutils always generate .rela relocations. Keep smiling - * if it's empty, abort otherwise. - */ - if (!sechdrs[relsec].sh_size) - return 0; - - printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", - me->name); - return -ENOEXEC; -} diff --git a/arch/mips/kernel/module-elf64.c b/arch/mips/kernel/module-elf64.c deleted file mode 100644 index e804792ee1e..00000000000 --- a/arch/mips/kernel/module-elf64.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Copyright (C) 2001 Rusty Russell. - * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org) - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include - -struct mips_hi16 { - struct mips_hi16 *next; - Elf32_Addr *addr; - Elf64_Addr value; -}; - -static struct mips_hi16 *mips_hi16_list; - -void *module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - return vmalloc(size); -} - - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ -} - -int module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod) -{ - return 0; -} - -int apply_relocate(Elf64_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - /* - * We don't want to deal with REL relocations - RELA is so much saner. - */ - if (!sechdrs[relsec].sh_size) - return 0; - - printk(KERN_ERR "module %s: REL relocation unsupported\n", - me->name); - return -ENOEXEC; -} - -static int apply_r_mips_none(struct module *me, uint32_t *location, - Elf64_Addr v) -{ - return 0; -} - -static int apply_r_mips_32(struct module *me, uint32_t *location, - Elf64_Addr v) -{ - *location = v; - - return 0; -} - -static int apply_r_mips_26(struct module *me, uint32_t *location, - Elf64_Addr v) -{ - if (v % 4) { - printk(KERN_ERR "module %s: dangerous relocation\n", me->name); - return -ENOEXEC; - } - - if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { - printk(KERN_ERR - "module %s: relocation overflow\n", - me->name); - return -ENOEXEC; - } - - *location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff); - - return 0; -} - -static int apply_r_mips_hi16(struct module *me, uint32_t *location, - Elf64_Addr v) -{ - struct mips_hi16 *n; - - /* - * We cannot relocate this one now because we don't know the value of - * the carry we need to add. Save the information, and let LO16 do the - * actual relocation. - */ - n = kmalloc(sizeof *n, GFP_KERNEL); - if (!n) - return -ENOMEM; - - n->addr = location; - n->value = v; - n->next = mips_hi16_list; - mips_hi16_list = n; - - return 0; -} - -static int apply_r_mips_lo16(struct module *me, uint32_t *location, - Elf64_Addr v) -{ - unsigned long insnlo = *location; - Elf32_Addr val, vallo; - - /* Sign extend the addend we extract from the lo insn. */ - vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; - - if (mips_hi16_list != NULL) { - struct mips_hi16 *l; - - l = mips_hi16_list; - while (l != NULL) { - struct mips_hi16 *next; - unsigned long insn; - - /* - * The value for the HI16 had best be the same. - */ - if (v != l->value) - goto out_danger; - - /* - * Do the HI16 relocation. Note that we actually don't - * need to know anything about the LO16 itself, except - * where to find the low 16 bits of the addend needed - * by the LO16. - */ - insn = *l->addr; - val = ((insn & 0xffff) << 16) + vallo; - val += v; - - /* - * Account for the sign extension that will happen in - * the low bits. - */ - val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff; - - insn = (insn & ~0xffff) | val; - *l->addr = insn; - - next = l->next; - kfree(l); - l = next; - } - - mips_hi16_list = NULL; - } - - /* - * Ok, we're done with the HI16 relocs. Now deal with the LO16. - */ - insnlo = (insnlo & ~0xffff) | (v & 0xffff); - *location = insnlo; - - return 0; - -out_danger: - printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name); - - return -ENOEXEC; -} - -static int apply_r_mips_64(struct module *me, uint32_t *location, - Elf64_Addr v) -{ - *(uint64_t *) location = v; - - return 0; -} - - -static int apply_r_mips_higher(struct module *me, uint32_t *location, - Elf64_Addr v) -{ - *location = (*location & 0xffff0000) | - ((((long long) v + 0x80008000LL) >> 32) & 0xffff); - - return 0; -} - -static int apply_r_mips_highest(struct module *me, uint32_t *location, - Elf64_Addr v) -{ - *location = (*location & 0xffff0000) | - ((((long long) v + 0x800080008000LL) >> 48) & 0xffff); - - return 0; -} - -static int (*reloc_handlers[]) (struct module *me, uint32_t *location, - Elf64_Addr v) = { - [R_MIPS_NONE] = apply_r_mips_none, - [R_MIPS_32] = apply_r_mips_32, - [R_MIPS_26] = apply_r_mips_26, - [R_MIPS_HI16] = apply_r_mips_hi16, - [R_MIPS_LO16] = apply_r_mips_lo16, - [R_MIPS_64] = apply_r_mips_64, - [R_MIPS_HIGHER] = apply_r_mips_higher, - [R_MIPS_HIGHEST] = apply_r_mips_highest -}; - -int apply_relocate_add(Elf64_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - Elf64_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr; - Elf64_Sym *sym; - uint32_t *location; - unsigned int i; - Elf64_Addr v; - int res; - - pr_debug("Applying relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); - - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rel[i].r_offset; - /* This is the symbol it is referring to */ - sym = (Elf64_Sym *)sechdrs[symindex].sh_addr + rel[i].r_sym; - if (!sym->st_value) { - printk(KERN_WARNING "%s: Unknown symbol %s\n", - me->name, strtab + sym->st_name); - return -ENOENT; - } - - v = sym->st_value; - - res = reloc_handlers[rel[i].r_type](me, location, v); - if (res) - return res; - } - - return 0; -} diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index 458af3c7a63..e54a7f442f8 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c @@ -1,9 +1,345 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2001 Rusty Russell. + * Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2005 Thiemo Seufer + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include #include #include +struct mips_hi16 { + struct mips_hi16 *next; + Elf_Addr *addr; + Elf_Addr value; +}; + +static struct mips_hi16 *mips_hi16_list; + static LIST_HEAD(dbe_list); static DEFINE_SPINLOCK(dbe_lock); +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) +{ + return 0; +} + +static int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v) +{ + return 0; +} + +static int apply_r_mips_32_rel(struct module *me, u32 *location, Elf_Addr v) +{ + *location += v; + + return 0; +} + +static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v) +{ + *location = v; + + return 0; +} + +static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) +{ + if (v % 4) { + printk(KERN_ERR "module %s: dangerous relocation\n", me->name); + return -ENOEXEC; + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { + printk(KERN_ERR + "module %s: relocation overflow\n", + me->name); + return -ENOEXEC; + } + + *location = (*location & ~0x03ffffff) | + ((*location + (v >> 2)) & 0x03ffffff); + + return 0; +} + +static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v) +{ + if (v % 4) { + printk(KERN_ERR "module %s: dangerous relocation\n", me->name); + return -ENOEXEC; + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { + printk(KERN_ERR + "module %s: relocation overflow\n", + me->name); + return -ENOEXEC; + } + + *location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff); + + return 0; +} + +static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v) +{ + struct mips_hi16 *n; + + /* + * We cannot relocate this one now because we don't know the value of + * the carry we need to add. Save the information, and let LO16 do the + * actual relocation. + */ + n = kmalloc(sizeof *n, GFP_KERNEL); + if (!n) + return -ENOMEM; + + n->addr = (Elf_Addr *)location; + n->value = v; + n->next = mips_hi16_list; + mips_hi16_list = n; + + return 0; +} + +static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v) +{ + *location = (*location & 0xffff0000) | + ((((long long) v + 0x8000LL) >> 16) & 0xffff); + + return 0; +} + +static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) +{ + unsigned long insnlo = *location; + Elf_Addr val, vallo; + + /* Sign extend the addend we extract from the lo insn. */ + vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; + + if (mips_hi16_list != NULL) { + struct mips_hi16 *l; + + l = mips_hi16_list; + while (l != NULL) { + struct mips_hi16 *next; + unsigned long insn; + + /* + * The value for the HI16 had best be the same. + */ + if (v != l->value) + goto out_danger; + + /* + * Do the HI16 relocation. Note that we actually don't + * need to know anything about the LO16 itself, except + * where to find the low 16 bits of the addend needed + * by the LO16. + */ + insn = *l->addr; + val = ((insn & 0xffff) << 16) + vallo; + val += v; + + /* + * Account for the sign extension that will happen in + * the low bits. + */ + val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff; + + insn = (insn & ~0xffff) | val; + *l->addr = insn; + + next = l->next; + kfree(l); + l = next; + } + + mips_hi16_list = NULL; + } + + /* + * Ok, we're done with the HI16 relocs. Now deal with the LO16. + */ + val = v + vallo; + insnlo = (insnlo & ~0xffff) | (val & 0xffff); + *location = insnlo; + + return 0; + +out_danger: + printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name); + + return -ENOEXEC; +} + +static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v) +{ + *location = (*location & 0xffff0000) | (v & 0xffff); + + return 0; +} + +static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v) +{ + *(Elf_Addr *)location = v; + + return 0; +} + +static int apply_r_mips_higher_rela(struct module *me, u32 *location, + Elf_Addr v) +{ + *location = (*location & 0xffff0000) | + ((((long long) v + 0x80008000LL) >> 32) & 0xffff); + + return 0; +} + +static int apply_r_mips_highest_rela(struct module *me, u32 *location, + Elf_Addr v) +{ + *location = (*location & 0xffff0000) | + ((((long long) v + 0x800080008000LL) >> 48) & 0xffff); + + return 0; +} + +static int (*reloc_handlers_rel[]) (struct module *me, u32 *location, + Elf_Addr v) = { + [R_MIPS_NONE] = apply_r_mips_none, + [R_MIPS_32] = apply_r_mips_32_rel, + [R_MIPS_26] = apply_r_mips_26_rel, + [R_MIPS_HI16] = apply_r_mips_hi16_rel, + [R_MIPS_LO16] = apply_r_mips_lo16_rel +}; + +static int (*reloc_handlers_rela[]) (struct module *me, u32 *location, + Elf_Addr v) = { + [R_MIPS_NONE] = apply_r_mips_none, + [R_MIPS_32] = apply_r_mips_32_rela, + [R_MIPS_26] = apply_r_mips_26_rela, + [R_MIPS_HI16] = apply_r_mips_hi16_rela, + [R_MIPS_LO16] = apply_r_mips_lo16_rela, + [R_MIPS_64] = apply_r_mips_64_rela, + [R_MIPS_HIGHER] = apply_r_mips_higher_rela, + [R_MIPS_HIGHEST] = apply_r_mips_highest_rela +}; + +int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, + struct module *me) +{ + Elf_Mips_Rel *rel = (void *) sechdrs[relsec].sh_addr; + Elf_Sym *sym; + u32 *location; + unsigned int i; + Elf_Addr v; + int res; + + pr_debug("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset; + /* This is the symbol it is referring to */ + sym = (Elf_Sym *)sechdrs[symindex].sh_addr + + ELF_MIPS_R_SYM(rel[i]); + if (!sym->st_value) { + printk(KERN_WARNING "%s: Unknown symbol %s\n", + me->name, strtab + sym->st_name); + return -ENOENT; + } + + v = sym->st_value; + + res = reloc_handlers_rel[ELF_MIPS_R_TYPE(rel[i])](me, location, v); + if (res) + return res; + } + + return 0; +} + +int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, + unsigned int symindex, unsigned int relsec, + struct module *me) +{ + Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr; + Elf_Sym *sym; + u32 *location; + unsigned int i; + Elf_Addr v; + int res; + + pr_debug("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset; + /* This is the symbol it is referring to */ + sym = (Elf_Sym *)sechdrs[symindex].sh_addr + + ELF_MIPS_R_SYM(rel[i]); + if (!sym->st_value) { + printk(KERN_WARNING "%s: Unknown symbol %s\n", + me->name, strtab + sym->st_name); + return -ENOENT; + } + + v = sym->st_value + rel[i].r_addend; + + res = reloc_handlers_rela[ELF_MIPS_R_TYPE(rel[i])](me, location, v); + if (res) + return res; + } + + return 0; +} + /* Given an address, look for it in the module exception tables. */ const struct exception_table_entry *search_module_dbetables(unsigned long addr) { -- cgit v1.2.3 From dc953df1ba5526814982676f47580c8e1bcdbfeb Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Mon, 21 Feb 2005 10:55:16 +0000 Subject: Fix wchan implementation, based on earlier by from Atsushi Nemoto. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 135 ++++++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 58 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index e4f2f801138..f99efce556e 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -211,22 +211,48 @@ long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); } -struct mips_frame_info { +static struct mips_frame_info { + void *func; + int omit_fp; /* compiled without fno-omit-frame-pointer */ int frame_offset; int pc_offset; +} schedule_frame, mfinfo[] = { + { schedule, 0 }, /* must be first */ + /* arch/mips/kernel/semaphore.c */ + { __down, 1 }, + { __down_interruptible, 1 }, + /* kernel/sched.c */ +#ifdef CONFIG_PREEMPT + { preempt_schedule, 0 }, +#endif + { wait_for_completion, 0 }, + { interruptible_sleep_on, 0 }, + { interruptible_sleep_on_timeout, 0 }, + { sleep_on, 0 }, + { sleep_on_timeout, 0 }, + { yield, 0 }, + { io_schedule, 0 }, + { io_schedule_timeout, 0 }, +#if defined(CONFIG_SMP) && defined(CONFIG_PREEMPT) + { __preempt_spin_lock, 0 }, + { __preempt_write_lock, 0 }, +#endif + /* kernel/timer.c */ + { schedule_timeout, 1 }, +/* { nanosleep_restart, 1 }, */ + /* lib/rwsem-spinlock.c */ + { __down_read, 1 }, + { __down_write, 1 }, }; -static struct mips_frame_info schedule_frame; -static struct mips_frame_info schedule_timeout_frame; -static struct mips_frame_info sleep_on_frame; -static struct mips_frame_info sleep_on_timeout_frame; -static struct mips_frame_info wait_for_completion_frame; + static int mips_frame_info_initialized; -static int __init get_frame_info(struct mips_frame_info *info, void *func) +static int __init get_frame_info(struct mips_frame_info *info) { int i; + void *func = info->func; union mips_instruction *ip = (union mips_instruction *)func; info->pc_offset = -1; - info->frame_offset = -1; + info->frame_offset = info->omit_fp ? 0 : -1; for (i = 0; i < 128; i++, ip++) { /* if jal, jalr, jr, stop. */ if (ip->j_format.opcode == jal_op || @@ -247,14 +273,16 @@ static int __init get_frame_info(struct mips_frame_info *info, void *func) /* sw / sd $ra, offset($sp) */ if (ip->i_format.rt == 31) { if (info->pc_offset != -1) - break; + continue; info->pc_offset = ip->i_format.simmediate / sizeof(long); } /* sw / sd $s8, offset($sp) */ if (ip->i_format.rt == 30) { +//#if 0 /* gcc 3.4 does aggressive optimization... */ if (info->frame_offset != -1) - break; + continue; +//#endif info->frame_offset = ip->i_format.simmediate / sizeof(long); } @@ -272,13 +300,25 @@ static int __init get_frame_info(struct mips_frame_info *info, void *func) static int __init frame_info_init(void) { - mips_frame_info_initialized = - !get_frame_info(&schedule_frame, schedule) && - !get_frame_info(&schedule_timeout_frame, schedule_timeout) && - !get_frame_info(&sleep_on_frame, sleep_on) && - !get_frame_info(&sleep_on_timeout_frame, sleep_on_timeout) && - !get_frame_info(&wait_for_completion_frame, wait_for_completion); - + int i, found; + for (i = 0; i < ARRAY_SIZE(mfinfo); i++) + if (get_frame_info(&mfinfo[i])) + return -1; + schedule_frame = mfinfo[0]; + /* bubble sort */ + do { + struct mips_frame_info tmp; + found = 0; + for (i = 1; i < ARRAY_SIZE(mfinfo); i++) { + if (mfinfo[i-1].func > mfinfo[i].func) { + tmp = mfinfo[i]; + mfinfo[i] = mfinfo[i-1]; + mfinfo[i-1] = tmp; + found = 1; + } + } + } while (found); + mips_frame_info_initialized = 1; return 0; } @@ -303,60 +343,39 @@ unsigned long thread_saved_pc(struct task_struct *tsk) /* get_wchan - a maintenance nightmare^W^Wpain in the ass ... */ unsigned long get_wchan(struct task_struct *p) { + unsigned long stack_page; unsigned long frame, pc; if (!p || p == current || p->state == TASK_RUNNING) return 0; - if (!mips_frame_info_initialized) + stack_page = (unsigned long)p->thread_info; + if (!stack_page || !mips_frame_info_initialized) return 0; + pc = thread_saved_pc(p); if (!in_sched_functions(pc)) - goto out; - - if (pc >= (unsigned long) sleep_on_timeout) - goto schedule_timeout_caller; - if (pc >= (unsigned long) sleep_on) - goto schedule_caller; - if (pc >= (unsigned long) interruptible_sleep_on_timeout) - goto schedule_timeout_caller; - if (pc >= (unsigned long)interruptible_sleep_on) - goto schedule_caller; - if (pc >= (unsigned long)wait_for_completion) - goto schedule_caller; - goto schedule_timeout_caller; - -schedule_caller: - frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset]; - if (pc >= (unsigned long) sleep_on) - pc = ((unsigned long *)frame)[sleep_on_frame.pc_offset]; - else - pc = ((unsigned long *)frame)[wait_for_completion_frame.pc_offset]; - goto out; + return pc; -schedule_timeout_caller: - /* - * The schedule_timeout frame - */ frame = ((unsigned long *)p->thread.reg30)[schedule_frame.frame_offset]; + do { + int i; - /* - * frame now points to sleep_on_timeout's frame - */ - pc = ((unsigned long *)frame)[schedule_timeout_frame.pc_offset]; + if (frame < stack_page || frame > stack_page + THREAD_SIZE - 32) + return 0; - if (in_sched_functions(pc)) { - /* schedule_timeout called by [interruptible_]sleep_on_timeout */ - frame = ((unsigned long *)frame)[schedule_timeout_frame.frame_offset]; - pc = ((unsigned long *)frame)[sleep_on_timeout_frame.pc_offset]; - } - -out: + for (i = ARRAY_SIZE(mfinfo) - 1; i >= 0; i--) { + if (pc >= (unsigned long) mfinfo[i].func) + break; + } + if (i < 0) + break; -#ifdef CONFIG_64BIT - if (current->thread.mflags & MF_32BIT_REGS) /* Kludge for 32-bit ps */ - pc &= 0xffffffffUL; -#endif + if (mfinfo[i].omit_fp) + break; + pc = ((unsigned long *)frame)[mfinfo[i].pc_offset]; + frame = ((unsigned long *)frame)[mfinfo[i].frame_offset]; + } while (in_sched_functions(pc)); return pc; } -- cgit v1.2.3 From 0ac354801a879181471331c5b9be021bf5b9d515 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 21 Feb 2005 21:34:24 +0000 Subject: On multiprocessor systems the BogoMIPS for each CPU was reported was the value for the last CPU having calibrated it's delay loop. Signed-off-by: Ralf Baechle --- arch/mips/kernel/proc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 0f159f30e89..760fcdfea18 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -105,8 +105,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) (version >> 4) & 0x0f, version & 0x0f, (fp_vers >> 4) & 0x0f, fp_vers & 0x0f); seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n", - loops_per_jiffy / (500000/HZ), - (loops_per_jiffy / (5000/HZ)) % 100); + cpu_data[n].udelay_val / (500000/HZ), + (cpu_data[n].udelay_val / (5000/HZ)) % 100); seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no"); seq_printf(m, "microsecond timers\t: %s\n", cpu_has_counter ? "yes" : "no"); -- cgit v1.2.3 From b727a60258730b331519fedda503a8da78638791 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 22 Feb 2005 21:18:01 +0000 Subject: Merge do_boot_cpu() into the new style __cpu_up(). Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 1d3a4b50194..d1828ef5ffd 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -248,23 +248,28 @@ void __devinit smp_prepare_boot_cpu(void) } /* - * Startup the CPU with this logical number + * Called once for each "cpu_possible(cpu)". Needs to spin up the cpu + * and keep control until "cpu_online(cpu)" is set. Note: cpu is + * physical, not logical. */ -static int __init do_boot_cpu(int cpu) +int __devinit __cpu_up(unsigned int cpu) { struct task_struct *idle; /* + * Processor goes to start_secondary(), sets online flag * The following code is purely to make sure * Linux can schedule processes on this slave. */ idle = fork_idle(cpu); if (IS_ERR(idle)) - panic("failed fork for CPU %d\n", cpu); + panic(KERN_ERR "Fork failed for CPU %d", cpu); prom_boot_secondary(cpu, idle); - /* XXXKW timeout */ + /* + * Trust is futile. We should really have timeouts ... + */ while (!cpu_isset(cpu, cpu_callin_map)) udelay(100); @@ -273,23 +278,6 @@ static int __init do_boot_cpu(int cpu) return 0; } -/* - * Called once for each "cpu_possible(cpu)". Needs to spin up the cpu - * and keep control until "cpu_online(cpu)" is set. Note: cpu is - * physical, not logical. - */ -int __devinit __cpu_up(unsigned int cpu) -{ - int ret; - - /* Processor goes to start_secondary(), sets online flag */ - ret = do_boot_cpu(cpu); - if (ret < 0) - return ret; - - return 0; -} - /* Not really SMP stuff ... */ int setup_profiling_timer(unsigned int multiplier) { -- cgit v1.2.3 From 8ab00b9a02c55fd6263c5f7c0dc88389d94de327 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 28 Feb 2005 13:39:57 +0000 Subject: Convert struct hw_interrupt_type initializations to ISO C99 named initializers. Signed-off-by: Ralf Baechle --- arch/mips/kernel/i8259.c | 15 +++++++-------- arch/mips/kernel/irq-msc01.c | 30 ++++++++++++++---------------- arch/mips/kernel/irq-mv6434x.c | 15 +++++++-------- arch/mips/kernel/irq-rm7000.c | 14 +++++++------- arch/mips/kernel/irq-rm9000.c | 28 ++++++++++++++-------------- arch/mips/kernel/irq_cpu.c | 15 +++++++-------- 6 files changed, 56 insertions(+), 61 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 447759201d1..bb31370cd39 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -52,14 +52,13 @@ static unsigned int startup_8259A_irq(unsigned int irq) } static struct hw_interrupt_type i8259A_irq_type = { - "XT-PIC", - startup_8259A_irq, - shutdown_8259A_irq, - enable_8259A_irq, - disable_8259A_irq, - mask_and_ack_8259A, - end_8259A_irq, - NULL + .typename = "XT-PIC", + .startup = startup_8259A_irq, + .shutdown = shutdown_8259A_irq, + .enable = enable_8259A_irq, + .disable = disable_8259A_irq, + .ack = mask_and_ack_8259A, + .end = end_8259A_irq, }; /* diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index 43c00ac0b88..bf759e33c5e 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c @@ -129,25 +129,23 @@ msc_bind_eic_interrupt (unsigned int irq, unsigned int set) #define shutdown_msc_irq disable_msc_irq struct hw_interrupt_type msc_levelirq_type = { - "SOC-it-Level", - startup_msc_irq, - shutdown_msc_irq, - enable_msc_irq, - disable_msc_irq, - level_mask_and_ack_msc_irq, - end_msc_irq, - NULL + .typename = "SOC-it-Level", + .startup = startup_msc_irq, + .shutdown = shutdown_msc_irq, + .enable = enable_msc_irq, + .disable = disable_msc_irq, + .ack = level_mask_and_ack_msc_irq, + .end = end_msc_irq, }; struct hw_interrupt_type msc_edgeirq_type = { - "SOC-it-Edge", - startup_msc_irq, - shutdown_msc_irq, - enable_msc_irq, - disable_msc_irq, - edge_mask_and_ack_msc_irq, - end_msc_irq, - NULL + .typename = "SOC-it-Edge", + .startup =startup_msc_irq, + .shutdown = shutdown_msc_irq, + .enable = enable_msc_irq, + .disable = disable_msc_irq, + .ack = edge_mask_and_ack_msc_irq, + .end = end_msc_irq, }; diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c index 088bbbc869e..0ac067f45cf 100644 --- a/arch/mips/kernel/irq-mv6434x.c +++ b/arch/mips/kernel/irq-mv6434x.c @@ -135,14 +135,13 @@ void ll_mv64340_irq(struct pt_regs *regs) #define shutdown_mv64340_irq disable_mv64340_irq struct hw_interrupt_type mv64340_irq_type = { - "MV-64340", - startup_mv64340_irq, - shutdown_mv64340_irq, - enable_mv64340_irq, - disable_mv64340_irq, - mask_and_ack_mv64340_irq, - end_mv64340_irq, - NULL + .typename = "MV-64340", + .startup = startup_mv64340_irq, + .shutdown = shutdown_mv64340_irq, + .enable = enable_mv64340_irq, + .disable = disable_mv64340_irq, + .ack = mask_and_ack_mv64340_irq, + .end = end_mv64340_irq, }; void __init mv64340_irq_init(unsigned int base) diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c index f5d779fd035..0b130c5ac5d 100644 --- a/arch/mips/kernel/irq-rm7000.c +++ b/arch/mips/kernel/irq-rm7000.c @@ -72,13 +72,13 @@ static void rm7k_cpu_irq_end(unsigned int irq) } static hw_irq_controller rm7k_irq_controller = { - "RM7000", - rm7k_cpu_irq_startup, - rm7k_cpu_irq_shutdown, - rm7k_cpu_irq_enable, - rm7k_cpu_irq_disable, - rm7k_cpu_irq_ack, - rm7k_cpu_irq_end, + .typename = "RM7000", + .startup = rm7k_cpu_irq_startup, + .shutdown = rm7k_cpu_irq_shutdown, + .enable = rm7k_cpu_irq_enable, + .disable = rm7k_cpu_irq_disable, + .ack = rm7k_cpu_irq_ack, + .end = rm7k_cpu_irq_end, }; void __init rm7k_cpu_irq_init(int base) diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c index bdd13029625..9b5f20c32ac 100644 --- a/arch/mips/kernel/irq-rm9000.c +++ b/arch/mips/kernel/irq-rm9000.c @@ -106,23 +106,23 @@ static void rm9k_cpu_irq_end(unsigned int irq) } static hw_irq_controller rm9k_irq_controller = { - "RM9000", - rm9k_cpu_irq_startup, - rm9k_cpu_irq_shutdown, - rm9k_cpu_irq_enable, - rm9k_cpu_irq_disable, - rm9k_cpu_irq_ack, - rm9k_cpu_irq_end, + .typename = "RM9000", + .startup = rm9k_cpu_irq_startup, + .shutdown = rm9k_cpu_irq_shutdown, + .enable = rm9k_cpu_irq_enable, + .disable = rm9k_cpu_irq_disable, + .ack = rm9k_cpu_irq_ack, + .end = rm9k_cpu_irq_end, }; static hw_irq_controller rm9k_perfcounter_irq = { - "RM9000", - rm9k_perfcounter_irq_startup, - rm9k_perfcounter_irq_shutdown, - rm9k_cpu_irq_enable, - rm9k_cpu_irq_disable, - rm9k_cpu_irq_ack, - rm9k_cpu_irq_end, + .typename = "RM9000", + .startup = rm9k_perfcounter_irq_startup, + .shutdown = rm9k_perfcounter_irq_shutdown, + .enable = rm9k_cpu_irq_enable, + .disable = rm9k_cpu_irq_disable, + .ack = rm9k_cpu_irq_ack, + .end = rm9k_cpu_irq_end, }; unsigned int rm9000_perfcount_irq; diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 8f8c15fa748..905ff843a68 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -93,14 +93,13 @@ static void mips_cpu_irq_end(unsigned int irq) } static hw_irq_controller mips_cpu_irq_controller = { - "MIPS", - mips_cpu_irq_startup, - mips_cpu_irq_shutdown, - mips_cpu_irq_enable, - mips_cpu_irq_disable, - mips_cpu_irq_ack, - mips_cpu_irq_end, - NULL /* no affinity stuff for UP */ + .typename = "MIPS", + .startup = mips_cpu_irq_startup, + .shutdown = mips_cpu_irq_shutdown, + .enable = mips_cpu_irq_enable, + .disable = mips_cpu_irq_disable, + .ack = mips_cpu_irq_ack, + .end = mips_cpu_irq_end, }; -- cgit v1.2.3 From 784f7b9d895893c6aa3ca471c1344a62fc29c285 Mon Sep 17 00:00:00 2001 From: "Steven J. Hill" Date: Tue, 1 Mar 2005 03:51:33 +0000 Subject: Fix 'prctl' system call for IRIX. At this point IRIX 5.3 static binaries are now working for 80% of the ones I have tried. The other ones that do not work all fail in the same way with the same messages. Once that bug is tracked down, we should be in good shape. Task locking still needs some work. Signed-off-by: Ralf Baechle --- arch/mips/kernel/sysirix.c | 60 +++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 33 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 7ae4af47697..ed7c0e3c2f8 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -73,32 +73,30 @@ asmlinkage int irix_sysmp(struct pt_regs *regs) } /* The prctl commands. */ -#define PR_MAXPROCS 1 /* Tasks/user. */ -#define PR_ISBLOCKED 2 /* If blocked, return 1. */ -#define PR_SETSTACKSIZE 3 /* Set largest task stack size. */ -#define PR_GETSTACKSIZE 4 /* Get largest task stack size. */ -#define PR_MAXPPROCS 5 /* Num parallel tasks. */ -#define PR_UNBLKONEXEC 6 /* When task exec/exit's, unblock. */ -#define PR_SETEXITSIG 8 /* When task exit's, set signal. */ -#define PR_RESIDENT 9 /* Make task unswappable. */ -#define PR_ATTACHADDR 10 /* (Re-)Connect a vma to a task. */ -#define PR_DETACHADDR 11 /* Disconnect a vma from a task. */ -#define PR_TERMCHILD 12 /* When parent sleeps with fishes, kill child. */ -#define PR_GETSHMASK 13 /* Get the sproc() share mask. */ -#define PR_GETNSHARE 14 /* Number of share group members. */ -#define PR_COREPID 15 /* Add task pid to name when it core. */ -#define PR_ATTACHADDRPERM 16 /* (Re-)Connect vma, with specified prot. */ -#define PR_PTHREADEXIT 17 /* Kill a pthread without prejudice. */ - -asmlinkage int irix_prctl(struct pt_regs *regs) -{ - unsigned long cmd; - int error = 0, base = 0; +#define PR_MAXPROCS 1 /* Tasks/user. */ +#define PR_ISBLOCKED 2 /* If blocked, return 1. */ +#define PR_SETSTACKSIZE 3 /* Set largest task stack size. */ +#define PR_GETSTACKSIZE 4 /* Get largest task stack size. */ +#define PR_MAXPPROCS 5 /* Num parallel tasks. */ +#define PR_UNBLKONEXEC 6 /* When task exec/exit's, unblock. */ +#define PR_SETEXITSIG 8 /* When task exit's, set signal. */ +#define PR_RESIDENT 9 /* Make task unswappable. */ +#define PR_ATTACHADDR 10 /* (Re-)Connect a vma to a task. */ +#define PR_DETACHADDR 11 /* Disconnect a vma from a task. */ +#define PR_TERMCHILD 12 /* Kill child if the parent dies. */ +#define PR_GETSHMASK 13 /* Get the sproc() share mask. */ +#define PR_GETNSHARE 14 /* Number of share group members. */ +#define PR_COREPID 15 /* Add task pid to name when it core. */ +#define PR_ATTACHADDRPERM 16 /* (Re-)Connect vma, with specified prot. */ +#define PR_PTHREADEXIT 17 /* Kill a pthread, only for IRIX 6.[234] */ + +asmlinkage int irix_prctl(unsigned option, ...) +{ + va_list args; + int error = 0; - if (regs->regs[2] == 1000) - base = 1; - cmd = regs->regs[base + 4]; - switch (cmd) { + va_start(args, option); + switch (option) { case PR_MAXPROCS: printk("irix_prctl[%s:%d]: Wants PR_MAXPROCS\n", current->comm, current->pid); @@ -111,7 +109,7 @@ asmlinkage int irix_prctl(struct pt_regs *regs) printk("irix_prctl[%s:%d]: Wants PR_ISBLOCKED\n", current->comm, current->pid); read_lock(&tasklist_lock); - task = find_task_by_pid(regs->regs[base + 5]); + task = find_task_by_pid(va_arg(args, pid_t)); error = -ESRCH; if (error) error = (task->run_list.next != NULL); @@ -121,7 +119,7 @@ asmlinkage int irix_prctl(struct pt_regs *regs) } case PR_SETSTACKSIZE: { - long value = regs->regs[base + 5]; + long value = va_arg(args, long); printk("irix_prctl[%s:%d]: Wants PR_SETSTACKSIZE<%08lx>\n", current->comm, current->pid, (unsigned long) value); @@ -222,17 +220,13 @@ asmlinkage int irix_prctl(struct pt_regs *regs) error = -EINVAL; break; - case PR_PTHREADEXIT: - printk("irix_prctl[%s:%d]: Wants PR_PTHREADEXIT\n", - current->comm, current->pid); - do_exit(regs->regs[base + 5]); - default: printk("irix_prctl[%s:%d]: Non-existant opcode %d\n", - current->comm, current->pid, (int)cmd); + current->comm, current->pid, option); error = -EINVAL; break; } + va_end(args); return error; } -- cgit v1.2.3 From e3ad1c23ba72214669b364c6fa304531dc768c3e Mon Sep 17 00:00:00 2001 From: Pete Popov Date: Tue, 1 Mar 2005 06:33:16 +0000 Subject: Base Au1200 2.6 support. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 5 +++++ arch/mips/kernel/proc.c | 3 +++ 2 files changed, 8 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 7685f8baf3f..66c2a2788ff 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -116,6 +116,8 @@ static inline void check_wait(void) case CPU_AU1000: case CPU_AU1100: case CPU_AU1500: + case CPU_AU1550: + case CPU_AU1200: if (au1k_wait_ptr != NULL) { cpu_wait = au1k_wait_ptr; printk(" available.\n"); @@ -505,6 +507,9 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) case 3: c->cputype = CPU_AU1550; break; + case 4: + c->cputype = CPU_AU1200; + break; default: panic("Unknown Au Core!"); break; diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 760fcdfea18..13888520d41 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -60,6 +60,9 @@ static const char *cpu_name[] = { [CPU_TX3927] "TX3927", [CPU_AU1000] "Au1000", [CPU_AU1500] "Au1500", + [CPU_AU1100] "Au1100", + [CPU_AU1550] "Au1550", + [CPU_AU1200] "Au1200", [CPU_4KEC] "MIPS 4KEc", [CPU_4KSC] "MIPS 4KSc", [CPU_VR41XX] "NEC Vr41xx", -- cgit v1.2.3 From 0f04afb59565c3029563b9a79b3513c9f3327a27 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 1 Mar 2005 10:38:58 +0000 Subject: ISOify. Signed-off-by: Ralf Baechle --- arch/mips/kernel/proc.c | 120 ++++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 60 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 13888520d41..d1290b1ec40 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -19,66 +19,66 @@ unsigned int vced_count, vcei_count; static const char *cpu_name[] = { - [CPU_UNKNOWN] "unknown", - [CPU_R2000] "R2000", - [CPU_R3000] "R3000", - [CPU_R3000A] "R3000A", - [CPU_R3041] "R3041", - [CPU_R3051] "R3051", - [CPU_R3052] "R3052", - [CPU_R3081] "R3081", - [CPU_R3081E] "R3081E", - [CPU_R4000PC] "R4000PC", - [CPU_R4000SC] "R4000SC", - [CPU_R4000MC] "R4000MC", - [CPU_R4200] "R4200", - [CPU_R4400PC] "R4400PC", - [CPU_R4400SC] "R4400SC", - [CPU_R4400MC] "R4400MC", - [CPU_R4600] "R4600", - [CPU_R6000] "R6000", - [CPU_R6000A] "R6000A", - [CPU_R8000] "R8000", - [CPU_R10000] "R10000", - [CPU_R12000] "R12000", - [CPU_R4300] "R4300", - [CPU_R4650] "R4650", - [CPU_R4700] "R4700", - [CPU_R5000] "R5000", - [CPU_R5000A] "R5000A", - [CPU_R4640] "R4640", - [CPU_NEVADA] "Nevada", - [CPU_RM7000] "RM7000", - [CPU_RM9000] "RM9000", - [CPU_R5432] "R5432", - [CPU_4KC] "MIPS 4Kc", - [CPU_5KC] "MIPS 5Kc", - [CPU_R4310] "R4310", - [CPU_SB1] "SiByte SB1", - [CPU_TX3912] "TX3912", - [CPU_TX3922] "TX3922", - [CPU_TX3927] "TX3927", - [CPU_AU1000] "Au1000", - [CPU_AU1500] "Au1500", - [CPU_AU1100] "Au1100", - [CPU_AU1550] "Au1550", - [CPU_AU1200] "Au1200", - [CPU_4KEC] "MIPS 4KEc", - [CPU_4KSC] "MIPS 4KSc", - [CPU_VR41XX] "NEC Vr41xx", - [CPU_R5500] "R5500", - [CPU_TX49XX] "TX49xx", - [CPU_20KC] "MIPS 20Kc", - [CPU_24K] "MIPS 24K", - [CPU_25KF] "MIPS 25Kf", - [CPU_VR4111] "NEC VR4111", - [CPU_VR4121] "NEC VR4121", - [CPU_VR4122] "NEC VR4122", - [CPU_VR4131] "NEC VR4131", - [CPU_VR4133] "NEC VR4133", - [CPU_VR4181] "NEC VR4181", - [CPU_VR4181A] "NEC VR4181A", - [CPU_SR71000] "Sandcraft SR71000" + [CPU_UNKNOWN] = "unknown", + [CPU_R2000] = "R2000", + [CPU_R3000] = "R3000", + [CPU_R3000A] = "R3000A", + [CPU_R3041] = "R3041", + [CPU_R3051] = "R3051", + [CPU_R3052] = "R3052", + [CPU_R3081] = "R3081", + [CPU_R3081E] = "R3081E", + [CPU_R4000PC] = "R4000PC", + [CPU_R4000SC] = "R4000SC", + [CPU_R4000MC] = "R4000MC", + [CPU_R4200] = "R4200", + [CPU_R4400PC] = "R4400PC", + [CPU_R4400SC] = "R4400SC", + [CPU_R4400MC] = "R4400MC", + [CPU_R4600] = "R4600", + [CPU_R6000] = "R6000", + [CPU_R6000A] = "R6000A", + [CPU_R8000] = "R8000", + [CPU_R10000] = "R10000", + [CPU_R12000] = "R12000", + [CPU_R4300] = "R4300", + [CPU_R4650] = "R4650", + [CPU_R4700] = "R4700", + [CPU_R5000] = "R5000", + [CPU_R5000A] = "R5000A", + [CPU_R4640] = "R4640", + [CPU_NEVADA] = "Nevada", + [CPU_RM7000] = "RM7000", + [CPU_RM9000] = "RM9000", + [CPU_R5432] = "R5432", + [CPU_4KC] = "MIPS 4Kc", + [CPU_5KC] = "MIPS 5Kc", + [CPU_R4310] = "R4310", + [CPU_SB1] = "SiByte SB1", + [CPU_TX3912] = "TX3912", + [CPU_TX3922] = "TX3922", + [CPU_TX3927] = "TX3927", + [CPU_AU1000] = "Au1000", + [CPU_AU1500] = "Au1500", + [CPU_AU1100] = "Au1100", + [CPU_AU1550] = "Au1550", + [CPU_AU1200] = "Au1200", + [CPU_4KEC] = "MIPS 4KEc", + [CPU_4KSC] = "MIPS 4KSc", + [CPU_VR41XX] = "NEC Vr41xx", + [CPU_R5500] = "R5500", + [CPU_TX49XX] = "TX49xx", + [CPU_20KC] = "MIPS 20Kc", + [CPU_24K] = "MIPS 24K", + [CPU_25KF] = "MIPS 25Kf", + [CPU_VR4111] = "NEC VR4111", + [CPU_VR4121] = "NEC VR4121", + [CPU_VR4122] = "NEC VR4122", + [CPU_VR4131] = "NEC VR4131", + [CPU_VR4133] = "NEC VR4133", + [CPU_VR4181] = "NEC VR4181", + [CPU_VR4181A] = "NEC VR4181A", + [CPU_SR71000] = "Sandcraft SR71000" }; -- cgit v1.2.3 From 14f18b7f7e58de9a34c4b5fd38d5f73f22fba7ac Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 1 Mar 2005 18:15:08 +0000 Subject: On 24K we did always disable cache parity protection - obviously not the greatest thing to do. Try to enable parity protection, check if we actually succeeded and print a message about the outcome of this. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index a53b1ed7b38..d06db5f8115 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -736,16 +736,12 @@ static inline void parity_protection_init(void) { switch (current_cpu_data.cputype) { case CPU_24K: - /* 24K cache parity not currently implemented in FPGA */ - printk(KERN_INFO "Disable cache parity protection for " - "MIPS 24K CPU.\n"); - write_c0_ecc(read_c0_ecc() & ~0x80000000); - break; case CPU_5KC: - /* Set the PE bit (bit 31) in the c0_ecc register. */ - printk(KERN_INFO "Enable cache parity protection for " - "MIPS 5KC/24K CPUs.\n"); - write_c0_ecc(read_c0_ecc() | 0x80000000); + write_c0_ecc(0x80000000); + back_to_back_c0_hazard(); + /* Set the PE bit (bit 31) in the c0_errctl register. */ + printk(KERN_INFO "Cache parity protection %sabled\n", + (read_c0_ecc() & 0x80000000) ? "en" : "dis"); break; case CPU_20KC: case CPU_25KF: -- cgit v1.2.3 From fe00f943e0ef98b4057abcc2940d631a975b43cd Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 1 Mar 2005 19:22:29 +0000 Subject: Sparseify MIPS. Signed-off-by: Ralf Baechle --- arch/mips/kernel/i8259.c | 2 +- arch/mips/kernel/irixelf.c | 14 +- arch/mips/kernel/irixinv.c | 7 +- arch/mips/kernel/irixsig.c | 408 +++++++++++++++++++----------------- arch/mips/kernel/process.c | 8 - arch/mips/kernel/ptrace.c | 4 +- arch/mips/kernel/signal.c | 14 +- arch/mips/kernel/sysirix.c | 479 +++++++++++++++++++++---------------------- arch/mips/kernel/traps.c | 21 +- arch/mips/kernel/unaligned.c | 10 +- 10 files changed, 489 insertions(+), 478 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index bb31370cd39..a7d2aac46ee 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -321,7 +321,7 @@ void __init init_i8259_irqs (void) for (i = 0; i < 16; i++) { irq_desc[i].status = IRQ_DISABLED; - irq_desc[i].action = 0; + irq_desc[i].action = NULL; irq_desc[i].depth = 1; irq_desc[i].handler = &i8259A_irq_type; } diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 881f125eecb..5aeacc1ffb2 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -147,7 +147,7 @@ static void padzero(unsigned long elf_bss) nbyte = elf_bss & (PAGE_SIZE-1); if (nbyte) { nbyte = PAGE_SIZE - nbyte; - clear_user((void *) elf_bss, nbyte); + clear_user((void __user *) elf_bss, nbyte); } } @@ -878,10 +878,10 @@ static int load_irix_library(struct file *file) * phdrs there are in the USER_PHDRP array. We return the vaddr the * first phdr was successfully mapped to. */ -unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) +unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt) { unsigned long type, vaddr, filesz, offset, flags; - struct elf_phdr *hp; + struct elf_phdr __user *hp; struct file *filp; int i, retval; @@ -968,9 +968,9 @@ unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt) /* These are the only things you should do on a core-file: use only these * functions to write out all the necessary info. */ -static int dump_write(struct file *file, const void *addr, int nr) +static int dump_write(struct file *file, const void __user *addr, int nr) { - return file->f_op->write(file, (const char *) addr, nr, &file->f_pos) == nr; + return file->f_op->write(file, (const char __user *) addr, nr, &file->f_pos) == nr; } static int dump_seek(struct file *file, off_t off) @@ -1204,7 +1204,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) len = current->mm->arg_end - current->mm->arg_start; len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; (void *) copy_from_user(&psinfo.pr_psargs, - (const char *)current->mm->arg_start, len); + (const char __user *)current->mm->arg_start, len); for (i = 0; i < len; i++) if (psinfo.pr_psargs[i] == 0) psinfo.pr_psargs[i] = ' '; @@ -1301,7 +1301,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) #ifdef DEBUG printk("elf_core_dump: writing %08lx %lx\n", addr, len); #endif - DUMP_WRITE((void *)addr, len); + DUMP_WRITE((void __user *)addr, len); } if ((off_t) file->f_pos != offset) { diff --git a/arch/mips/kernel/irixinv.c b/arch/mips/kernel/irixinv.c index 60aa98cd179..de8584f6231 100644 --- a/arch/mips/kernel/irixinv.c +++ b/arch/mips/kernel/irixinv.c @@ -30,10 +30,10 @@ void add_to_inventory (int class, int type, int controller, int unit, int state) inventory_items++; } -int dump_inventory_to_user (void *userbuf, int size) +int dump_inventory_to_user (void __user *userbuf, int size) { inventory_t *inv = &inventory [0]; - inventory_t *user = userbuf; + inventory_t __user *user = userbuf; int v; if (!access_ok(VERIFY_WRITE, userbuf, size)) @@ -41,7 +41,8 @@ int dump_inventory_to_user (void *userbuf, int size) for (v = 0; v < inventory_items; v++){ inv = &inventory [v]; - copy_to_user (user, inv, sizeof (inventory_t)); + if (copy_to_user (user, inv, sizeof (inventory_t))) + return -EFAULT; user++; } return inventory_items * sizeof (inventory_t); diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c index eff89322ba5..908e6368420 100644 --- a/arch/mips/kernel/irixsig.c +++ b/arch/mips/kernel/irixsig.c @@ -76,36 +76,39 @@ static inline void dump_irix5_sigctx(struct sigctx_irix5 *c) } #endif -static void setup_irix_frame(struct k_sigaction *ka, struct pt_regs *regs, - int signr, sigset_t *oldmask) +static int setup_irix_frame(struct k_sigaction *ka, struct pt_regs *regs, + int signr, sigset_t *oldmask) { + struct sigctx_irix5 __user *ctx; unsigned long sp; - struct sigctx_irix5 *ctx; - int i; + int error, i; sp = regs->regs[29]; sp -= sizeof(struct sigctx_irix5); sp &= ~(0xf); - ctx = (struct sigctx_irix5 *) sp; + ctx = (struct sigctx_irix5 __user *) sp; if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx))) goto segv_and_exit; - __put_user(0, &ctx->weird_fpu_thing); - __put_user(~(0x00000001), &ctx->rmask); - __put_user(0, &ctx->regs[0]); + error = __put_user(0, &ctx->weird_fpu_thing); + error |= __put_user(~(0x00000001), &ctx->rmask); + error |= __put_user(0, &ctx->regs[0]); for(i = 1; i < 32; i++) - __put_user((u64) regs->regs[i], &ctx->regs[i]); + error |= __put_user((u64) regs->regs[i], &ctx->regs[i]); + + error |= __put_user((u64) regs->hi, &ctx->hi); + error |= __put_user((u64) regs->lo, &ctx->lo); + error |= __put_user((u64) regs->cp0_epc, &ctx->pc); + error |= __put_user(!!used_math(), &ctx->usedfp); + error |= __put_user((u64) regs->cp0_cause, &ctx->cp0_cause); + error |= __put_user((u64) regs->cp0_badvaddr, &ctx->cp0_badvaddr); - __put_user((u64) regs->hi, &ctx->hi); - __put_user((u64) regs->lo, &ctx->lo); - __put_user((u64) regs->cp0_epc, &ctx->pc); - __put_user(!!used_math(), &ctx->usedfp); - __put_user((u64) regs->cp0_cause, &ctx->cp0_cause); - __put_user((u64) regs->cp0_badvaddr, &ctx->cp0_badvaddr); + error |= __put_user(0, &ctx->sstk_flags); /* XXX sigstack unimp... todo... */ - __put_user(0, &ctx->sstk_flags); /* XXX sigstack unimp... todo... */ + error |= __copy_to_user(&ctx->sigset, oldmask, sizeof(irix_sigset_t)) ? -EFAULT : 0; - __copy_to_user(&ctx->sigset, oldmask, sizeof(irix_sigset_t)); + if (error) + goto segv_and_exit; #ifdef DEBUG_SIG dump_irix5_sigctx(ctx); @@ -117,13 +120,14 @@ static void setup_irix_frame(struct k_sigaction *ka, struct pt_regs *regs, regs->regs[7] = (unsigned long) ka->sa.sa_handler; regs->regs[25] = regs->cp0_epc = (unsigned long) ka->sa_restorer; - return; + return 1; segv_and_exit: force_sigsegv(signr, current); + return 0; } -static void inline +static int inline setup_irix_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *oldmask, siginfo_t *info) { @@ -131,9 +135,11 @@ setup_irix_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, do_exit(SIGSEGV); } -static inline void handle_signal(unsigned long sig, siginfo_t *info, +static inline int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) { + int ret; + switch(regs->regs[0]) { case ERESTARTNOHAND: regs->regs[2] = EINTR; @@ -151,9 +157,9 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, regs->regs[0] = 0; /* Don't deal with this again. */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_irix_rt_frame(ka, regs, sig, oldset, info); + ret = setup_irix_rt_frame(ka, regs, sig, oldset, info); else - setup_irix_frame(ka, regs, sig, oldset); + ret = setup_irix_frame(ka, regs, sig, oldset); spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -161,6 +167,8 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + + return ret; } asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs) @@ -184,10 +192,8 @@ asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs) oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); - if (signr > 0) { - handle_signal(signr, &info, &ka, oldset, regs); - return 1; - } + if (signr > 0) + return handle_signal(signr, &info, &ka, oldset, regs); no_signal: /* @@ -208,10 +214,11 @@ no_signal: asmlinkage void irix_sigreturn(struct pt_regs *regs) { - struct sigctx_irix5 *context, *magic; + struct sigctx_irix5 __user *context, *magic; unsigned long umask, mask; u64 *fregs; - int sig, i, base = 0; + u32 usedfp; + int error, sig, i, base = 0; sigset_t blocked; /* Always make any pending restarted system calls return -EINTR */ @@ -220,8 +227,8 @@ irix_sigreturn(struct pt_regs *regs) if (regs->regs[2] == 1000) base = 1; - context = (struct sigctx_irix5 *) regs->regs[base + 4]; - magic = (struct sigctx_irix5 *) regs->regs[base + 5]; + context = (struct sigctx_irix5 __user *) regs->regs[base + 4]; + magic = (struct sigctx_irix5 __user *) regs->regs[base + 5]; sig = (int) regs->regs[base + 6]; #ifdef DEBUG_SIG printk("[%s:%d] IRIX sigreturn(scp[%p],ucp[%p],sig[%d])\n", @@ -236,25 +243,31 @@ irix_sigreturn(struct pt_regs *regs) dump_irix5_sigctx(context); #endif - __get_user(regs->cp0_epc, &context->pc); - umask = context->rmask; mask = 2; + error = __get_user(regs->cp0_epc, &context->pc); + error |= __get_user(umask, &context->rmask); + + mask = 2; for (i = 1; i < 32; i++, mask <<= 1) { - if(umask & mask) - __get_user(regs->regs[i], &context->regs[i]); + if (umask & mask) + error |= __get_user(regs->regs[i], &context->regs[i]); } - __get_user(regs->hi, &context->hi); - __get_user(regs->lo, &context->lo); + error |= __get_user(regs->hi, &context->hi); + error |= __get_user(regs->lo, &context->lo); - if ((umask & 1) && context->usedfp) { + error |= __get_user(usedfp, &context->usedfp); + if ((umask & 1) && usedfp) { fregs = (u64 *) ¤t->thread.fpu; + for(i = 0; i < 32; i++) - fregs[i] = (u64) context->fpregs[i]; - __get_user(current->thread.fpu.hard.fcr31, &context->fpcsr); + error |= __get_user(fregs[i], &context->fpregs[i]); + error |= __get_user(current->thread.fpu.hard.fcr31, &context->fpcsr); } /* XXX do sigstack crapola here... XXX */ - if (__copy_from_user(&blocked, &context->sigset, sizeof(blocked))) + error |= __copy_from_user(&blocked, &context->sigset, sizeof(blocked)) ? -EFAULT : 0; + + if (error) goto badframe; sigdelsetmask(&blocked, ~_BLOCKABLE); @@ -296,8 +309,8 @@ static inline void dump_sigact_irix5(struct sigact_irix5 *p) #endif asmlinkage int -irix_sigaction(int sig, const struct sigaction *act, - struct sigaction *oact, void *trampoline) +irix_sigaction(int sig, const struct sigaction __user *act, + struct sigaction __user *oact, void __user *trampoline) { struct k_sigaction new_ka, old_ka; int ret; @@ -311,12 +324,16 @@ irix_sigaction(int sig, const struct sigaction *act, #endif if (act) { sigset_t mask; - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_flags, &act->sa_flags)) + int err; + + if (!access_ok(VERIFY_READ, act, sizeof(*act))) return -EFAULT; + err = __get_user(new_ka.sa.sa_handler, &act->sa_handler); + err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __copy_from_user(&mask, &act->sa_mask, sizeof(sigset_t)); + err |= __copy_from_user(&mask, &act->sa_mask, sizeof(sigset_t)) ? -EFAULT : 0; + if (err) + return err; /* * Hmmm... methinks IRIX libc always passes a valid trampoline @@ -330,30 +347,37 @@ irix_sigaction(int sig, const struct sigaction *act, ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_flags, &oact->sa_flags)) + int err; + + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) + return -EFAULT; + + err = __put_user(old_ka.sa.sa_handler, &oact->sa_handler); + err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + err |= __copy_to_user(&oact->sa_mask, &old_ka.sa.sa_mask, + sizeof(sigset_t)) ? -EFAULT : 0; + if (err) return -EFAULT; - __copy_to_user(&old_ka.sa.sa_mask, &oact->sa_mask, - sizeof(sigset_t)); } return ret; } -asmlinkage int irix_sigpending(irix_sigset_t *set) +asmlinkage int irix_sigpending(irix_sigset_t __user *set) { return do_sigpending(set, sizeof(*set)); } -asmlinkage int irix_sigprocmask(int how, irix_sigset_t *new, irix_sigset_t *old) +asmlinkage int irix_sigprocmask(int how, irix_sigset_t __user *new, + irix_sigset_t __user *old) { sigset_t oldbits, newbits; if (new) { if (!access_ok(VERIFY_READ, new, sizeof(*new))) return -EFAULT; - __copy_from_user(&newbits, new, sizeof(unsigned long)*4); + if (__copy_from_user(&newbits, new, sizeof(unsigned long)*4)) + return -EFAULT; sigdelsetmask(&newbits, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); @@ -381,20 +405,19 @@ asmlinkage int irix_sigprocmask(int how, irix_sigset_t *new, irix_sigset_t *old) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); } - if(old) { - if (!access_ok(VERIFY_WRITE, old, sizeof(*old))) - return -EFAULT; - __copy_to_user(old, ¤t->blocked, sizeof(unsigned long)*4); - } + if (old) + return copy_to_user(old, ¤t->blocked, + sizeof(unsigned long)*4) ? -EFAULT : 0; return 0; } asmlinkage int irix_sigsuspend(struct pt_regs *regs) { - sigset_t *uset, saveset, newset; + sigset_t saveset, newset; + sigset_t __user *uset; - uset = (sigset_t *) regs->regs[4]; + uset = (sigset_t __user *) regs->regs[4]; if (copy_from_user(&newset, uset, sizeof(sigset_t))) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); @@ -440,12 +463,13 @@ struct irix5_siginfo { } stuff; }; -asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, - struct timespec *tp) +asmlinkage int irix_sigpoll_sys(unsigned long __user *set, + struct irix5_siginfo __user *info, struct timespec __user *tp) { long expire = MAX_SCHEDULE_TIMEOUT; sigset_t kset; int i, sig, error, timeo = 0; + struct timespec ktp; #ifdef DEBUG_SIG printk("[%s:%d] irix_sigpoll_sys(%p,%p,%p)\n", @@ -456,14 +480,8 @@ asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, if (!set) return -EINVAL; - if (!access_ok(VERIFY_READ, set, sizeof(kset))) { - error = -EFAULT; - goto out; - } - - __copy_from_user(&kset, set, sizeof(set)); - if (error) - goto out; + if (copy_from_user(&kset, set, sizeof(set))) + return -EFAULT; if (info && clear_user(info, sizeof(*info))) { error = -EFAULT; @@ -471,19 +489,21 @@ asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, } if (tp) { - if (!access_ok(VERIFY_READ, tp, sizeof(*tp))) + if (copy_from_user(&ktp, tp, sizeof(*tp))) return -EFAULT; - if (!tp->tv_sec && !tp->tv_nsec) { - error = -EINVAL; - goto out; - } - expire = timespec_to_jiffies(tp) + (tp->tv_sec||tp->tv_nsec); + + if (!ktp.tv_sec && !ktp.tv_nsec) + return -EINVAL; + + expire = timespec_to_jiffies(&ktp) + + (ktp.tv_sec || ktp.tv_nsec); } while(1) { long tmp = 0; - expire = schedule_timeout_interruptible(expire); + current->state = TASK_INTERRUPTIBLE; + expire = schedule_timeout(expire); for (i=0; i<=4; i++) tmp |= (current->pending.signal.sig[i] & kset.sig[i]); @@ -500,15 +520,14 @@ asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, if (timeo) return -EAGAIN; - for(sig = 1; i <= 65 /* IRIX_NSIG */; sig++) { + for (sig = 1; i <= 65 /* IRIX_NSIG */; sig++) { if (sigismember (&kset, sig)) continue; if (sigismember (¤t->pending.signal, sig)) { /* XXX need more than this... */ if (info) - info->sig = sig; - error = 0; - goto out; + return copy_to_user(&info->sig, &sig, sizeof(sig)); + return 0; } } @@ -534,8 +553,9 @@ extern int getrusage(struct task_struct *, int, struct rusage __user *); #define W_MASK (W_EXITED | W_TRAPPED | W_STOPPED | W_CONT | W_NOHANG) -asmlinkage int irix_waitsys(int type, int pid, struct irix5_siginfo *info, - int options, struct rusage *ru) +asmlinkage int irix_waitsys(int type, int pid, + struct irix5_siginfo __user *info, int options, + struct rusage __user *ru) { int flag, retval; DECLARE_WAITQUEUE(wait, current); @@ -543,28 +563,22 @@ asmlinkage int irix_waitsys(int type, int pid, struct irix5_siginfo *info, struct task_struct *p; struct list_head *_p; - if (!info) { - retval = -EINVAL; - goto out; - } - if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) { - retval = -EFAULT; - goto out; - } - if (ru) { - if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru))) { - retval = -EFAULT; - goto out; - } - } - if (options & ~(W_MASK)) { - retval = -EINVAL; - goto out; - } - if (type != IRIX_P_PID && type != IRIX_P_PGID && type != IRIX_P_ALL) { - retval = -EINVAL; - goto out; - } + if (!info) + return -EINVAL; + + if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) + return -EFAULT; + + if (ru) + if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru))) + return -EFAULT; + + if (options & ~W_MASK) + return -EINVAL; + + if (type != IRIX_P_PID && type != IRIX_P_PGID && type != IRIX_P_ALL) + return -EINVAL; + add_wait_queue(¤t->signal->wait_chldexit, &wait); repeat: flag = 0; @@ -595,18 +609,20 @@ repeat: add_parent(p, p->parent); write_unlock_irq(&tasklist_lock); retval = ru ? getrusage(p, RUSAGE_BOTH, ru) : 0; - if (!retval && ru) { - retval |= __put_user(SIGCHLD, &info->sig); - retval |= __put_user(0, &info->code); - retval |= __put_user(p->pid, &info->stuff.procinfo.pid); - retval |= __put_user((p->exit_code >> 8) & 0xff, - &info->stuff.procinfo.procdata.child.status); - retval |= __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime); - retval |= __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime); - } - if (!retval) { - p->exit_code = 0; - } + if (retval) + goto end_waitsys; + + retval = __put_user(SIGCHLD, &info->sig); + retval |= __put_user(0, &info->code); + retval |= __put_user(p->pid, &info->stuff.procinfo.pid); + retval |= __put_user((p->exit_code >> 8) & 0xff, + &info->stuff.procinfo.procdata.child.status); + retval |= __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime); + retval |= __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime); + if (retval) + goto end_waitsys; + + p->exit_code = 0; goto end_waitsys; case EXIT_ZOMBIE: @@ -614,16 +630,18 @@ repeat: current->signal->cstime += p->stime + p->signal->cstime; if (ru != NULL) getrusage(p, RUSAGE_BOTH, ru); - __put_user(SIGCHLD, &info->sig); - __put_user(1, &info->code); /* CLD_EXITED */ - __put_user(p->pid, &info->stuff.procinfo.pid); - __put_user((p->exit_code >> 8) & 0xff, + retval = __put_user(SIGCHLD, &info->sig); + retval |= __put_user(1, &info->code); /* CLD_EXITED */ + retval |= __put_user(p->pid, &info->stuff.procinfo.pid); + retval |= __put_user((p->exit_code >> 8) & 0xff, &info->stuff.procinfo.procdata.child.status); - __put_user(p->utime, + retval |= __put_user(p->utime, &info->stuff.procinfo.procdata.child.utime); - __put_user(p->stime, + retval |= __put_user(p->stime, &info->stuff.procinfo.procdata.child.stime); - retval = 0; + if (retval) + return retval; + if (p->real_parent != p->parent) { write_lock_irq(&tasklist_lock); remove_parent(p); @@ -656,7 +674,6 @@ end_waitsys: current->state = TASK_RUNNING; remove_wait_queue(¤t->signal->wait_chldexit, &wait); -out: return retval; } @@ -675,39 +692,39 @@ struct irix5_context { asmlinkage int irix_getcontext(struct pt_regs *regs) { - int i, base = 0; - struct irix5_context *ctx; + int error, i, base = 0; + struct irix5_context __user *ctx; unsigned long flags; if (regs->regs[2] == 1000) base = 1; - ctx = (struct irix5_context *) regs->regs[base + 4]; + ctx = (struct irix5_context __user *) regs->regs[base + 4]; #ifdef DEBUG_SIG printk("[%s:%d] irix_getcontext(%p)\n", current->comm, current->pid, ctx); #endif - if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx))) + if (!access_ok(VERIFY_WRITE, ctx, sizeof(*ctx))); return -EFAULT; - __put_user(current->thread.irix_oldctx, &ctx->link); + error = __put_user(current->thread.irix_oldctx, &ctx->link); - __copy_to_user(&ctx->sigmask, ¤t->blocked, sizeof(irix_sigset_t)); + error |= __copy_to_user(&ctx->sigmask, ¤t->blocked, sizeof(irix_sigset_t)) ? -EFAULT : 0; /* XXX Do sigstack stuff someday... */ - __put_user(0, &ctx->stack.sp); - __put_user(0, &ctx->stack.size); - __put_user(0, &ctx->stack.flags); + error |= __put_user(0, &ctx->stack.sp); + error |= __put_user(0, &ctx->stack.size); + error |= __put_user(0, &ctx->stack.flags); - __put_user(0, &ctx->weird_graphics_thing); - __put_user(0, &ctx->regs[0]); + error |= __put_user(0, &ctx->weird_graphics_thing); + error |= __put_user(0, &ctx->regs[0]); for (i = 1; i < 32; i++) - __put_user(regs->regs[i], &ctx->regs[i]); - __put_user(regs->lo, &ctx->regs[32]); - __put_user(regs->hi, &ctx->regs[33]); - __put_user(regs->cp0_cause, &ctx->regs[34]); - __put_user(regs->cp0_epc, &ctx->regs[35]); + error |= __put_user(regs->regs[i], &ctx->regs[i]); + error |= __put_user(regs->lo, &ctx->regs[32]); + error |= __put_user(regs->hi, &ctx->regs[33]); + error |= __put_user(regs->cp0_cause, &ctx->regs[34]); + error |= __put_user(regs->cp0_epc, &ctx->regs[35]); flags = 0x0f; if (!used_math()) { @@ -716,119 +733,124 @@ asmlinkage int irix_getcontext(struct pt_regs *regs) /* XXX wheee... */ printk("Wheee, no code for saving IRIX FPU context yet.\n"); } - __put_user(flags, &ctx->flags); + error |= __put_user(flags, &ctx->flags); - return 0; + return error; } -asmlinkage unsigned long irix_setcontext(struct pt_regs *regs) +asmlinkage void irix_setcontext(struct pt_regs *regs) { - int error, base = 0; - struct irix5_context *ctx; + struct irix5_context __user *ctx; + int err, base = 0; + u32 flags; - if(regs->regs[2] == 1000) + if (regs->regs[2] == 1000) base = 1; - ctx = (struct irix5_context *) regs->regs[base + 4]; + ctx = (struct irix5_context __user *) regs->regs[base + 4]; #ifdef DEBUG_SIG printk("[%s:%d] irix_setcontext(%p)\n", current->comm, current->pid, ctx); #endif - if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx))) { - error = -EFAULT; - goto out; - } + if (!access_ok(VERIFY_READ, ctx, sizeof(*ctx))) + goto segv_and_exit; - if (ctx->flags & 0x02) { + err = __get_user(flags, &ctx->flags); + if (flags & 0x02) { /* XXX sigstack garbage, todo... */ printk("Wheee, cannot do sigstack stuff in setcontext\n"); } - if (ctx->flags & 0x04) { + if (flags & 0x04) { int i; /* XXX extra control block stuff... todo... */ - for(i = 1; i < 32; i++) - regs->regs[i] = ctx->regs[i]; - regs->lo = ctx->regs[32]; - regs->hi = ctx->regs[33]; - regs->cp0_epc = ctx->regs[35]; + for (i = 1; i < 32; i++) + err |= __get_user(regs->regs[i], &ctx->regs[i]); + err |= __get_user(regs->lo, &ctx->regs[32]); + err |= __get_user(regs->hi, &ctx->regs[33]); + err |= __get_user(regs->cp0_epc, &ctx->regs[35]); } - if (ctx->flags & 0x08) { + if (flags & 0x08) /* XXX fpu context, blah... */ - printk("Wheee, cannot restore FPU context yet...\n"); - } - current->thread.irix_oldctx = ctx->link; - error = regs->regs[2]; + printk(KERN_ERR "Wheee, cannot restore FPU context yet...\n"); -out: - return error; + err |= __get_user(current->thread.irix_oldctx, &ctx->link); + if (err) + goto segv_and_exit; + + /* + * Don't let your children do this ... + */ + if (current_thread_info()->flags & TIF_SYSCALL_TRACE) + do_syscall_trace(regs, 1); + __asm__ __volatile__( + "move\t$29,%0\n\t" + "j\tsyscall_exit" + :/* no outputs */ + :"r" (®s)); + /* Unreached */ + +segv_and_exit: + force_sigsegv(SIGSEGV, current); } -struct irix_sigstack { unsigned long sp; int status; }; +struct irix_sigstack { + unsigned long sp; + int status; +}; -asmlinkage int irix_sigstack(struct irix_sigstack *new, struct irix_sigstack *old) +asmlinkage int irix_sigstack(struct irix_sigstack __user *new, + struct irix_sigstack __user *old) { - int error = -EFAULT; - #ifdef DEBUG_SIG printk("[%s:%d] irix_sigstack(%p,%p)\n", current->comm, current->pid, new, old); #endif - if(new) { + if (new) { if (!access_ok(VERIFY_READ, new, sizeof(*new))) - goto out; + return -EFAULT; } - if(old) { + if (old) { if (!access_ok(VERIFY_WRITE, old, sizeof(*old))) - goto out; + return -EFAULT; } - error = 0; -out: - return error; + return 0; } struct irix_sigaltstack { unsigned long sp; int size; int status; }; -asmlinkage int irix_sigaltstack(struct irix_sigaltstack *new, - struct irix_sigaltstack *old) +asmlinkage int irix_sigaltstack(struct irix_sigaltstack __user *new, + struct irix_sigaltstack __user *old) { - int error = -EFAULT; - #ifdef DEBUG_SIG printk("[%s:%d] irix_sigaltstack(%p,%p)\n", current->comm, current->pid, new, old); #endif - if (new) { + if (new) if (!access_ok(VERIFY_READ, new, sizeof(*new))) - goto out; - } + return -EFAULT; if (old) { if (!access_ok(VERIFY_WRITE, old, sizeof(*old))) - goto out; + return -EFAULT; } - error = 0; - -out: - error = 0; - return error; + return 0; } struct irix_procset { int cmd, ltype, lid, rtype, rid; }; -asmlinkage int irix_sigsendset(struct irix_procset *pset, int sig) +asmlinkage int irix_sigsendset(struct irix_procset __user *pset, int sig) { if (!access_ok(VERIFY_READ, pset, sizeof(*pset))) return -EFAULT; - #ifdef DEBUG_SIG printk("[%s:%d] irix_sigsendset([%d,%d,%d,%d,%d],%d)\n", current->comm, current->pid, diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index f99efce556e..5223c4450e4 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -38,14 +38,6 @@ #include #include -/* - * We use this if we don't have any better idle routine.. - * (This to kill: kernel/platform.c. - */ -void default_idle (void) -{ -} - /* * The idle thread. There's no useful work to be done, so just try to conserve * power and have a low exit latency (ie sit in a loop waiting for somebody to diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 0b571a5b4b8..2c7fc7472fb 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -103,7 +103,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; if (copied != sizeof(tmp)) break; - ret = put_user(tmp,(unsigned long *) data); + ret = put_user(tmp,(unsigned long __user *) data); break; } @@ -180,7 +180,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; goto out_tsk; } - ret = put_user(tmp, (unsigned long *) data); + ret = put_user(tmp, (unsigned long __user *) data); break; } diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 0209c1dd142..eb127230cc9 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -47,9 +47,10 @@ save_static_function(sys_sigsuspend); __attribute_used__ noinline static int _sys_sigsuspend(nabi_no_regargs struct pt_regs regs) { - sigset_t *uset, saveset, newset; + sigset_t saveset, newset; + sigset_t __user *uset; - uset = (sigset_t *) regs.regs[4]; + uset = (sigset_t __user *) regs.regs[4]; if (copy_from_user(&newset, uset, sizeof(sigset_t))) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); @@ -75,7 +76,8 @@ save_static_function(sys_rt_sigsuspend); __attribute_used__ noinline static int _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) { - sigset_t *unewset, saveset, newset; + sigset_t saveset, newset; + sigset_t __user *unewset; size_t sigsetsize; /* XXX Don't preclude handling different sized sigset_t's. */ @@ -83,7 +85,7 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) if (sigsetsize != sizeof(sigset_t)) return -EINVAL; - unewset = (sigset_t *) regs.regs[4]; + unewset = (sigset_t __user *) regs.regs[4]; if (copy_from_user(&newset, unewset, sizeof(newset))) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); @@ -147,8 +149,8 @@ asmlinkage int sys_sigaction(int sig, const struct sigaction *act, asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs) { - const stack_t *uss = (const stack_t *) regs.regs[4]; - stack_t *uoss = (stack_t *) regs.regs[5]; + const stack_t __user *uss = (const stack_t __user *) regs.regs[4]; + stack_t __user *uoss = (stack_t __user *) regs.regs[5]; unsigned long usp = regs.regs[29]; return do_sigaltstack(uss, uoss, usp); diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index ed7c0e3c2f8..52924f8ce23 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -233,7 +233,7 @@ asmlinkage int irix_prctl(unsigned option, ...) #undef DEBUG_PROCGRPS -extern unsigned long irix_mapelf(int fd, struct elf_phdr *user_phdrp, int cnt); +extern unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt); extern int getrusage(struct task_struct *p, int who, struct rusage __user *ru); extern char *prom_getenv(char *name); extern long prom_setenv(char *name, char *value); @@ -270,23 +270,19 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) cmd = regs->regs[base + 4]; switch(cmd) { case SGI_SYSID: { - char *buf = (char *) regs->regs[base + 5]; + char __user *buf = (char __user *) regs->regs[base + 5]; /* XXX Use ethernet addr.... */ - retval = clear_user(buf, 64); + retval = clear_user(buf, 64) ? -EFAULT : 0; break; } #if 0 case SGI_RDNAME: { int pid = (int) regs->regs[base + 5]; - char *buf = (char *) regs->regs[base + 6]; + char __user *buf = (char __user *) regs->regs[base + 6]; struct task_struct *p; char tcomm[sizeof(current->comm)]; - if (!access_ok(VERIFY_WRITE, buf, sizeof(tcomm))) { - retval = -EFAULT; - break; - } read_lock(&tasklist_lock); p = find_task_by_pid(pid); if (!p) { @@ -298,34 +294,28 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) read_unlock(&tasklist_lock); /* XXX Need to check sizes. */ - copy_to_user(buf, tcomm, sizeof(tcomm)); - retval = 0; + retval = copy_to_user(buf, tcomm, sizeof(tcomm)) ? -EFAULT : 0; break; } case SGI_GETNVRAM: { - char *name = (char *) regs->regs[base+5]; - char *buf = (char *) regs->regs[base+6]; + char __user *name = (char __user *) regs->regs[base+5]; + char __user *buf = (char __user *) regs->regs[base+6]; char *value; return -EINVAL; /* til I fix it */ - if (!access_ok(VERIFY_WRITE, buf, 128)) { - retval = -EFAULT; - break; - } value = prom_getenv(name); /* PROM lock? */ if (!value) { retval = -EINVAL; break; } /* Do I strlen() for the length? */ - copy_to_user(buf, value, 128); - retval = 0; + retval = copy_to_user(buf, value, 128) ? -EFAULT : 0; break; } case SGI_SETNVRAM: { - char *name = (char *) regs->regs[base+5]; - char *value = (char *) regs->regs[base+6]; + char __user *name = (char __user *) regs->regs[base+5]; + char __user *value = (char __user *) regs->regs[base+6]; return -EINVAL; /* til I fix it */ retval = prom_setenv(name, value); /* XXX make sure retval conforms to syssgi(2) */ @@ -401,16 +391,16 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) case SGI_SETGROUPS: retval = sys_setgroups((int) regs->regs[base + 5], - (gid_t *) regs->regs[base + 6]); + (gid_t __user *) regs->regs[base + 6]); break; case SGI_GETGROUPS: retval = sys_getgroups((int) regs->regs[base + 5], - (gid_t *) regs->regs[base + 6]); + (gid_t __user *) regs->regs[base + 6]); break; case SGI_RUSAGE: { - struct rusage *ru = (struct rusage *) regs->regs[base + 6]; + struct rusage __user *ru = (struct rusage __user *) regs->regs[base + 6]; switch((int) regs->regs[base + 5]) { case 0: @@ -447,7 +437,7 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) case SGI_ELFMAP: retval = irix_mapelf((int) regs->regs[base + 5], - (struct elf_phdr *) regs->regs[base + 6], + (struct elf_phdr __user *) regs->regs[base + 6], (int) regs->regs[base + 7]); break; @@ -462,24 +452,24 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) case SGI_PHYSP: { unsigned long addr = regs->regs[base + 5]; - int *pageno = (int *) (regs->regs[base + 6]); + int __user *pageno = (int __user *) (regs->regs[base + 6]); struct mm_struct *mm = current->mm; pgd_t *pgdp; + pud_t *pudp; pmd_t *pmdp; pte_t *ptep; - if (!access_ok(VERIFY_WRITE, pageno, sizeof(int))) - return -EFAULT; - down_read(&mm->mmap_sem); pgdp = pgd_offset(mm, addr); - pmdp = pmd_offset(pgdp, addr); + pudp = pud_offset(pgdp, addr); + pmdp = pmd_offset(pudp, addr); ptep = pte_offset(pmdp, addr); retval = -EINVAL; if (ptep) { pte_t pte = *ptep; if (pte_val(pte) & (_PAGE_VALID | _PAGE_PRESENT)) { + /* b0rked on 64-bit */ retval = put_user((pte_val(pte) & PAGE_MASK) >> PAGE_SHIFT, pageno); } @@ -490,7 +480,7 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) case SGI_INVENT: { int arg1 = (int) regs->regs [base + 5]; - void *buffer = (void *) regs->regs [base + 6]; + void __user *buffer = (void __user *) regs->regs [base + 6]; int count = (int) regs->regs [base + 7]; switch (arg1) { @@ -686,8 +676,8 @@ asmlinkage int irix_pause(void) } /* XXX need more than this... */ -asmlinkage int irix_mount(char *dev_name, char *dir_name, unsigned long flags, - char *type, void *data, int datalen) +asmlinkage int irix_mount(char __user *dev_name, char __user *dir_name, + unsigned long flags, char __user *type, void __user *data, int datalen) { printk("[%s:%d] irix_mount(%p,%p,%08lx,%p,%p,%d)\n", current->comm, current->pid, @@ -702,8 +692,8 @@ struct irix_statfs { char f_fname[6], f_fpack[6]; }; -asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf, - int len, int fs_type) +asmlinkage int irix_statfs(const char __user *path, + struct irix_statfs __user *buf, int len, int fs_type) { struct nameidata nd; struct kstatfs kbuf; @@ -718,6 +708,7 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf, error = -EFAULT; goto out; } + error = user_path_walk(path, &nd); if (error) goto out; @@ -726,18 +717,17 @@ asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf, if (error) goto dput_and_out; - __put_user(kbuf.f_type, &buf->f_type); - __put_user(kbuf.f_bsize, &buf->f_bsize); - __put_user(kbuf.f_frsize, &buf->f_frsize); - __put_user(kbuf.f_blocks, &buf->f_blocks); - __put_user(kbuf.f_bfree, &buf->f_bfree); - __put_user(kbuf.f_files, &buf->f_files); - __put_user(kbuf.f_ffree, &buf->f_ffree); + error = __put_user(kbuf.f_type, &buf->f_type); + error |= __put_user(kbuf.f_bsize, &buf->f_bsize); + error |= __put_user(kbuf.f_frsize, &buf->f_frsize); + error |= __put_user(kbuf.f_blocks, &buf->f_blocks); + error |= __put_user(kbuf.f_bfree, &buf->f_bfree); + error |= __put_user(kbuf.f_files, &buf->f_files); + error |= __put_user(kbuf.f_ffree, &buf->f_ffree); for (i = 0; i < 6; i++) { - __put_user(0, &buf->f_fname[i]); - __put_user(0, &buf->f_fpack[i]); + error |= __put_user(0, &buf->f_fname[i]); + error |= __put_user(0, &buf->f_fpack[i]); } - error = 0; dput_and_out: path_release(&nd); @@ -745,7 +735,7 @@ out: return error; } -asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf) +asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs __user *buf) { struct kstatfs kbuf; struct file *file; @@ -755,6 +745,7 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf) error = -EFAULT; goto out; } + if (!(file = fget(fd))) { error = -EBADF; goto out; @@ -764,16 +755,17 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf) if (error) goto out_f; - __put_user(kbuf.f_type, &buf->f_type); - __put_user(kbuf.f_bsize, &buf->f_bsize); - __put_user(kbuf.f_frsize, &buf->f_frsize); - __put_user(kbuf.f_blocks, &buf->f_blocks); - __put_user(kbuf.f_bfree, &buf->f_bfree); - __put_user(kbuf.f_files, &buf->f_files); - __put_user(kbuf.f_ffree, &buf->f_ffree); - for(i = 0; i < 6; i++) { - __put_user(0, &buf->f_fname[i]); - __put_user(0, &buf->f_fpack[i]); + error = __put_user(kbuf.f_type, &buf->f_type); + error |= __put_user(kbuf.f_bsize, &buf->f_bsize); + error |= __put_user(kbuf.f_frsize, &buf->f_frsize); + error |= __put_user(kbuf.f_blocks, &buf->f_blocks); + error |= __put_user(kbuf.f_bfree, &buf->f_bfree); + error |= __put_user(kbuf.f_files, &buf->f_files); + error |= __put_user(kbuf.f_ffree, &buf->f_ffree); + + for (i = 0; i < 6; i++) { + error |= __put_user(0, &buf->f_fname[i]); + error |= __put_user(0, &buf->f_fpack[i]); } out_f: @@ -800,14 +792,15 @@ asmlinkage int irix_setpgrp(int flags) return error; } -asmlinkage int irix_times(struct tms * tbuf) +asmlinkage int irix_times(struct tms __user *tbuf) { int err = 0; if (tbuf) { if (!access_ok(VERIFY_WRITE,tbuf,sizeof *tbuf)) return -EFAULT; - err |= __put_user(current->utime, &tbuf->tms_utime); + + err = __put_user(current->utime, &tbuf->tms_utime); err |= __put_user(current->stime, &tbuf->tms_stime); err |= __put_user(current->signal->cutime, &tbuf->tms_cutime); err |= __put_user(current->signal->cstime, &tbuf->tms_cstime); @@ -823,13 +816,13 @@ asmlinkage int irix_exec(struct pt_regs *regs) if(regs->regs[2] == 1000) base = 1; - filename = getname((char *) (long)regs->regs[base + 4]); + filename = getname((char __user *) (long)regs->regs[base + 4]); error = PTR_ERR(filename); if (IS_ERR(filename)) return error; - error = do_execve(filename, (char **) (long)regs->regs[base + 5], - (char **) 0, regs); + error = do_execve(filename, (char __user * __user *) (long)regs->regs[base + 5], + NULL, regs); putname(filename); return error; @@ -842,12 +835,12 @@ asmlinkage int irix_exece(struct pt_regs *regs) if (regs->regs[2] == 1000) base = 1; - filename = getname((char *) (long)regs->regs[base + 4]); + filename = getname((char __user *) (long)regs->regs[base + 4]); error = PTR_ERR(filename); if (IS_ERR(filename)) return error; - error = do_execve(filename, (char **) (long)regs->regs[base + 5], - (char **) (long)regs->regs[base + 6], regs); + error = do_execve(filename, (char __user * __user *) (long)regs->regs[base + 5], + (char __user * __user *) (long)regs->regs[base + 6], regs); putname(filename); return error; @@ -903,22 +896,17 @@ asmlinkage int irix_socket(int family, int type, int protocol) return sys_socket(family, type, protocol); } -asmlinkage int irix_getdomainname(char *name, int len) +asmlinkage int irix_getdomainname(char __user *name, int len) { - int error; - - if (!access_ok(VERIFY_WRITE, name, len)) - return -EFAULT; + int err; down_read(&uts_sem); if (len > __NEW_UTS_LEN) len = __NEW_UTS_LEN; - error = 0; - if (copy_to_user(name, system_utsname.domainname, len)) - error = -EFAULT; + err = copy_to_user(name, system_utsname.domainname, len) ? -EFAULT : 0; up_read(&uts_sem); - return error; + return err; } asmlinkage unsigned long irix_getpagesize(void) @@ -934,12 +922,13 @@ asmlinkage int irix_msgsys(int opcode, unsigned long arg0, unsigned long arg1, case 0: return sys_msgget((key_t) arg0, (int) arg1); case 1: - return sys_msgctl((int) arg0, (int) arg1, (struct msqid_ds *)arg2); + return sys_msgctl((int) arg0, (int) arg1, + (struct msqid_ds __user *)arg2); case 2: - return sys_msgrcv((int) arg0, (struct msgbuf *) arg1, + return sys_msgrcv((int) arg0, (struct msgbuf __user *) arg1, (size_t) arg2, (long) arg3, (int) arg4); case 3: - return sys_msgsnd((int) arg0, (struct msgbuf *) arg1, + return sys_msgsnd((int) arg0, (struct msgbuf __user *) arg1, (size_t) arg2, (int) arg3); default: return -EINVAL; @@ -951,12 +940,13 @@ asmlinkage int irix_shmsys(int opcode, unsigned long arg0, unsigned long arg1, { switch (opcode) { case 0: - return do_shmat((int) arg0, (char *)arg1, (int) arg2, + return do_shmat((int) arg0, (char __user *) arg1, (int) arg2, (unsigned long *) arg3); case 1: - return sys_shmctl((int)arg0, (int)arg1, (struct shmid_ds *)arg2); + return sys_shmctl((int)arg0, (int)arg1, + (struct shmid_ds __user *)arg2); case 2: - return sys_shmdt((char *)arg0); + return sys_shmdt((char __user *)arg0); case 3: return sys_shmget((key_t) arg0, (int) arg1, (int) arg2); default: @@ -974,7 +964,7 @@ asmlinkage int irix_semsys(int opcode, unsigned long arg0, unsigned long arg1, case 1: return sys_semget((key_t) arg0, (int) arg1, (int) arg2); case 2: - return sys_semop((int) arg0, (struct sembuf *)arg1, + return sys_semop((int) arg0, (struct sembuf __user *)arg1, (unsigned int) arg2); default: return -EINVAL; @@ -992,15 +982,16 @@ static inline loff_t llseek(struct file *file, loff_t offset, int origin) lock_kernel(); retval = fn(file, offset, origin); unlock_kernel(); + return retval; } asmlinkage int irix_lseek64(int fd, int _unused, int offhi, int offlow, int origin) { - int retval; struct file * file; loff_t offset; + int retval; retval = -EBADF; file = fget(fd); @@ -1025,12 +1016,12 @@ asmlinkage int irix_sginap(int ticks) return 0; } -asmlinkage int irix_sgikopt(char *istring, char *ostring, int len) +asmlinkage int irix_sgikopt(char __user *istring, char __user *ostring, int len) { return -EINVAL; } -asmlinkage int irix_gettimeofday(struct timeval *tv) +asmlinkage int irix_gettimeofday(struct timeval __user *tv) { time_t sec; long nsec, seq; @@ -1071,7 +1062,7 @@ asmlinkage unsigned long irix_mmap32(unsigned long addr, size_t len, int prot, if (max_size > file->f_dentry->d_inode->i_size) { old_pos = sys_lseek (fd, max_size - 1, 0); - sys_write (fd, "", 1); + sys_write (fd, (void __user *) "", 1); sys_lseek (fd, old_pos, 0); } } @@ -1096,7 +1087,7 @@ asmlinkage int irix_madvise(unsigned long addr, int len, int behavior) return -EINVAL; } -asmlinkage int irix_pagelock(char *addr, int len, int op) +asmlinkage int irix_pagelock(char __user *addr, int len, int op) { printk("[%s:%d] Wheee.. irix_pagelock(%p,%d,%d)\n", current->comm, current->pid, addr, len, op); @@ -1136,7 +1127,7 @@ asmlinkage int irix_BSDsetpgrp(int pid, int pgrp) return error; } -asmlinkage int irix_systeminfo(int cmd, char *buf, int cnt) +asmlinkage int irix_systeminfo(int cmd, char __user *buf, int cnt) { printk("[%s:%d] Wheee.. irix_systeminfo(%d,%p,%d)\n", current->comm, current->pid, cmd, buf, cnt); @@ -1152,14 +1143,14 @@ struct iuname { char _unused3[257], _unused4[257], _unused5[257]; }; -asmlinkage int irix_uname(struct iuname *buf) +asmlinkage int irix_uname(struct iuname __user *buf) { down_read(&uts_sem); - if (copy_to_user(system_utsname.sysname, buf->sysname, 65) - || copy_to_user(system_utsname.nodename, buf->nodename, 65) - || copy_to_user(system_utsname.release, buf->release, 65) - || copy_to_user(system_utsname.version, buf->version, 65) - || copy_to_user(system_utsname.machine, buf->machine, 65)) { + if (copy_from_user(system_utsname.sysname, buf->sysname, 65) + || copy_from_user(system_utsname.nodename, buf->nodename, 65) + || copy_from_user(system_utsname.release, buf->release, 65) + || copy_from_user(system_utsname.version, buf->version, 65) + || copy_from_user(system_utsname.machine, buf->machine, 65)) { return -EFAULT; } up_read(&uts_sem); @@ -1169,7 +1160,7 @@ asmlinkage int irix_uname(struct iuname *buf) #undef DEBUG_XSTAT -static int irix_xstat32_xlate(struct kstat *stat, void *ubuf) +static int irix_xstat32_xlate(struct kstat *stat, void __user *ubuf) { struct xstat32 { u32 st_dev, st_pad1[3], st_ino, st_mode, st_nlink, st_uid, st_gid; @@ -1209,7 +1200,7 @@ static int irix_xstat32_xlate(struct kstat *stat, void *ubuf) return copy_to_user(ubuf, &ub, sizeof(ub)) ? -EFAULT : 0; } -static int irix_xstat64_xlate(struct kstat *stat, void *ubuf) +static int irix_xstat64_xlate(struct kstat *stat, void __user *ubuf) { struct xstat64 { u32 st_dev; s32 st_pad1[3]; @@ -1259,7 +1250,7 @@ static int irix_xstat64_xlate(struct kstat *stat, void *ubuf) return copy_to_user(ubuf, &ks, sizeof(ks)) ? -EFAULT : 0; } -asmlinkage int irix_xstat(int version, char *filename, struct stat *statbuf) +asmlinkage int irix_xstat(int version, char __user *filename, struct stat __user *statbuf) { int retval; struct kstat stat; @@ -1285,7 +1276,7 @@ asmlinkage int irix_xstat(int version, char *filename, struct stat *statbuf) return retval; } -asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf) +asmlinkage int irix_lxstat(int version, char __user *filename, struct stat __user *statbuf) { int error; struct kstat stat; @@ -1312,7 +1303,7 @@ asmlinkage int irix_lxstat(int version, char *filename, struct stat *statbuf) return error; } -asmlinkage int irix_fxstat(int version, int fd, struct stat *statbuf) +asmlinkage int irix_fxstat(int version, int fd, struct stat __user *statbuf) { int error; struct kstat stat; @@ -1338,7 +1329,7 @@ asmlinkage int irix_fxstat(int version, int fd, struct stat *statbuf) return error; } -asmlinkage int irix_xmknod(int ver, char *filename, int mode, unsigned dev) +asmlinkage int irix_xmknod(int ver, char __user *filename, int mode, unsigned dev) { int retval; printk("[%s:%d] Wheee.. irix_xmknod(%d,%s,%x,%x)\n", @@ -1358,7 +1349,7 @@ asmlinkage int irix_xmknod(int ver, char *filename, int mode, unsigned dev) return retval; } -asmlinkage int irix_swapctl(int cmd, char *arg) +asmlinkage int irix_swapctl(int cmd, char __user *arg) { printk("[%s:%d] Wheee.. irix_swapctl(%d,%p)\n", current->comm, current->pid, cmd, arg); @@ -1374,7 +1365,7 @@ struct irix_statvfs { char f_fstr[32]; u32 f_filler[16]; }; -asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf) +asmlinkage int irix_statvfs(char __user *fname, struct irix_statvfs __user *buf) { struct nameidata nd; struct kstatfs kbuf; @@ -1382,10 +1373,9 @@ asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf) printk("[%s:%d] Wheee.. irix_statvfs(%s,%p)\n", current->comm, current->pid, fname, buf); - if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) { - error = -EFAULT; - goto out; - } + if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) + return -EFAULT; + error = user_path_walk(fname, &nd); if (error) goto out; @@ -1393,27 +1383,25 @@ asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf) if (error) goto dput_and_out; - __put_user(kbuf.f_bsize, &buf->f_bsize); - __put_user(kbuf.f_frsize, &buf->f_frsize); - __put_user(kbuf.f_blocks, &buf->f_blocks); - __put_user(kbuf.f_bfree, &buf->f_bfree); - __put_user(kbuf.f_bfree, &buf->f_bavail); /* XXX hackety hack... */ - __put_user(kbuf.f_files, &buf->f_files); - __put_user(kbuf.f_ffree, &buf->f_ffree); - __put_user(kbuf.f_ffree, &buf->f_favail); /* XXX hackety hack... */ + error |= __put_user(kbuf.f_bsize, &buf->f_bsize); + error |= __put_user(kbuf.f_frsize, &buf->f_frsize); + error |= __put_user(kbuf.f_blocks, &buf->f_blocks); + error |= __put_user(kbuf.f_bfree, &buf->f_bfree); + error |= __put_user(kbuf.f_bfree, &buf->f_bavail); /* XXX hackety hack... */ + error |= __put_user(kbuf.f_files, &buf->f_files); + error |= __put_user(kbuf.f_ffree, &buf->f_ffree); + error |= __put_user(kbuf.f_ffree, &buf->f_favail); /* XXX hackety hack... */ #ifdef __MIPSEB__ - __put_user(kbuf.f_fsid.val[1], &buf->f_fsid); + error |= __put_user(kbuf.f_fsid.val[1], &buf->f_fsid); #else - __put_user(kbuf.f_fsid.val[0], &buf->f_fsid); + error |= __put_user(kbuf.f_fsid.val[0], &buf->f_fsid); #endif for (i = 0; i < 16; i++) - __put_user(0, &buf->f_basetype[i]); - __put_user(0, &buf->f_flag); - __put_user(kbuf.f_namelen, &buf->f_namemax); + error |= __put_user(0, &buf->f_basetype[i]); + error |= __put_user(0, &buf->f_flag); + error |= __put_user(kbuf.f_namelen, &buf->f_namemax); for (i = 0; i < 32; i++) - __put_user(0, &buf->f_fstr[i]); - - error = 0; + error |= __put_user(0, &buf->f_fstr[i]); dput_and_out: path_release(&nd); @@ -1421,7 +1409,7 @@ out: return error; } -asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf) +asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs __user *buf) { struct kstatfs kbuf; struct file *file; @@ -1430,10 +1418,9 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf) printk("[%s:%d] Wheee.. irix_fstatvfs(%d,%p)\n", current->comm, current->pid, fd, buf); - if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) { - error = -EFAULT; - goto out; - } + if (!access_ok(VERIFY_WRITE, buf, sizeof(struct irix_statvfs))) + return -EFAULT; + if (!(file = fget(fd))) { error = -EBADF; goto out; @@ -1442,24 +1429,24 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf) if (error) goto out_f; - __put_user(kbuf.f_bsize, &buf->f_bsize); - __put_user(kbuf.f_frsize, &buf->f_frsize); - __put_user(kbuf.f_blocks, &buf->f_blocks); - __put_user(kbuf.f_bfree, &buf->f_bfree); - __put_user(kbuf.f_bfree, &buf->f_bavail); /* XXX hackety hack... */ - __put_user(kbuf.f_files, &buf->f_files); - __put_user(kbuf.f_ffree, &buf->f_ffree); - __put_user(kbuf.f_ffree, &buf->f_favail); /* XXX hackety hack... */ + error = __put_user(kbuf.f_bsize, &buf->f_bsize); + error |= __put_user(kbuf.f_frsize, &buf->f_frsize); + error |= __put_user(kbuf.f_blocks, &buf->f_blocks); + error |= __put_user(kbuf.f_bfree, &buf->f_bfree); + error |= __put_user(kbuf.f_bfree, &buf->f_bavail); /* XXX hackety hack... */ + error |= __put_user(kbuf.f_files, &buf->f_files); + error |= __put_user(kbuf.f_ffree, &buf->f_ffree); + error |= __put_user(kbuf.f_ffree, &buf->f_favail); /* XXX hackety hack... */ #ifdef __MIPSEB__ - __put_user(kbuf.f_fsid.val[1], &buf->f_fsid); + error |= __put_user(kbuf.f_fsid.val[1], &buf->f_fsid); #else - __put_user(kbuf.f_fsid.val[0], &buf->f_fsid); + error |= __put_user(kbuf.f_fsid.val[0], &buf->f_fsid); #endif for(i = 0; i < 16; i++) - __put_user(0, &buf->f_basetype[i]); - __put_user(0, &buf->f_flag); - __put_user(kbuf.f_namelen, &buf->f_namemax); - __clear_user(&buf->f_fstr, sizeof(buf->f_fstr)); + error |= __put_user(0, &buf->f_basetype[i]); + error |= __put_user(0, &buf->f_flag); + error |= __put_user(kbuf.f_namelen, &buf->f_namemax); + error |= __clear_user(&buf->f_fstr, sizeof(buf->f_fstr)) ? -EFAULT : 0; out_f: fput(file); @@ -1483,7 +1470,7 @@ asmlinkage int irix_sigqueue(int pid, int sig, int code, int val) return -EINVAL; } -asmlinkage int irix_truncate64(char *name, int pad, int size1, int size2) +asmlinkage int irix_truncate64(char __user *name, int pad, int size1, int size2) { int retval; @@ -1516,6 +1503,7 @@ asmlinkage int irix_mmap64(struct pt_regs *regs) int len, prot, flags, fd, off1, off2, error, base = 0; unsigned long addr, pgoff, *sp; struct file *file = NULL; + int err; if (regs->regs[2] == 1000) base = 1; @@ -1525,36 +1513,31 @@ asmlinkage int irix_mmap64(struct pt_regs *regs) prot = regs->regs[base + 6]; if (!base) { flags = regs->regs[base + 7]; - if (!access_ok(VERIFY_READ, sp, (4 * sizeof(unsigned long)))) { - error = -EFAULT; - goto out; - } + if (!access_ok(VERIFY_READ, sp, (4 * sizeof(unsigned long)))) + return -EFAULT; fd = sp[0]; - __get_user(off1, &sp[1]); - __get_user(off2, &sp[2]); + err = __get_user(off1, &sp[1]); + err |= __get_user(off2, &sp[2]); } else { - if (!access_ok(VERIFY_READ, sp, (5 * sizeof(unsigned long)))) { - error = -EFAULT; - goto out; - } - __get_user(flags, &sp[0]); - __get_user(fd, &sp[1]); - __get_user(off1, &sp[2]); - __get_user(off2, &sp[3]); + if (!access_ok(VERIFY_READ, sp, (5 * sizeof(unsigned long)))) + return -EFAULT; + err = __get_user(flags, &sp[0]); + err |= __get_user(fd, &sp[1]); + err |= __get_user(off1, &sp[2]); + err |= __get_user(off2, &sp[3]); } - if (off1 & PAGE_MASK) { - error = -EOVERFLOW; - goto out; - } + if (err) + return err; + + if (off1 & PAGE_MASK) + return -EOVERFLOW; pgoff = (off1 << (32 - PAGE_SHIFT)) | (off2 >> PAGE_SHIFT); if (!(flags & MAP_ANONYMOUS)) { - if (!(file = fget(fd))) { - error = -EBADF; - goto out; - } + if (!(file = fget(fd))) + return -EBADF; /* Ok, bad taste hack follows, try to think in something else when reading this */ @@ -1564,7 +1547,7 @@ asmlinkage int irix_mmap64(struct pt_regs *regs) if (max_size > file->f_dentry->d_inode->i_size) { old_pos = sys_lseek (fd, max_size - 1, 0); - sys_write (fd, "", 1); + sys_write (fd, (void __user *) "", 1); sys_lseek (fd, old_pos, 0); } } @@ -1579,7 +1562,6 @@ asmlinkage int irix_mmap64(struct pt_regs *regs) if (file) fput(file); -out: return error; } @@ -1591,7 +1573,7 @@ asmlinkage int irix_dmi(struct pt_regs *regs) return -EINVAL; } -asmlinkage int irix_pread(int fd, char *buf, int cnt, int off64, +asmlinkage int irix_pread(int fd, char __user *buf, int cnt, int off64, int off1, int off2) { printk("[%s:%d] Wheee.. irix_pread(%d,%p,%d,%d,%d,%d)\n", @@ -1600,7 +1582,7 @@ asmlinkage int irix_pread(int fd, char *buf, int cnt, int off64, return -EINVAL; } -asmlinkage int irix_pwrite(int fd, char *buf, int cnt, int off64, +asmlinkage int irix_pwrite(int fd, char __user *buf, int cnt, int off64, int off1, int off2) { printk("[%s:%d] Wheee.. irix_pwrite(%d,%p,%d,%d,%d,%d)\n", @@ -1632,7 +1614,7 @@ struct irix_statvfs64 { u32 f_filler[16]; }; -asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf) +asmlinkage int irix_statvfs64(char __user *fname, struct irix_statvfs64 __user *buf) { struct nameidata nd; struct kstatfs kbuf; @@ -1644,6 +1626,7 @@ asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf) error = -EFAULT; goto out; } + error = user_path_walk(fname, &nd); if (error) goto out; @@ -1651,27 +1634,25 @@ asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf) if (error) goto dput_and_out; - __put_user(kbuf.f_bsize, &buf->f_bsize); - __put_user(kbuf.f_frsize, &buf->f_frsize); - __put_user(kbuf.f_blocks, &buf->f_blocks); - __put_user(kbuf.f_bfree, &buf->f_bfree); - __put_user(kbuf.f_bfree, &buf->f_bavail); /* XXX hackety hack... */ - __put_user(kbuf.f_files, &buf->f_files); - __put_user(kbuf.f_ffree, &buf->f_ffree); - __put_user(kbuf.f_ffree, &buf->f_favail); /* XXX hackety hack... */ + error = __put_user(kbuf.f_bsize, &buf->f_bsize); + error |= __put_user(kbuf.f_frsize, &buf->f_frsize); + error |= __put_user(kbuf.f_blocks, &buf->f_blocks); + error |= __put_user(kbuf.f_bfree, &buf->f_bfree); + error |= __put_user(kbuf.f_bfree, &buf->f_bavail); /* XXX hackety hack... */ + error |= __put_user(kbuf.f_files, &buf->f_files); + error |= __put_user(kbuf.f_ffree, &buf->f_ffree); + error |= __put_user(kbuf.f_ffree, &buf->f_favail); /* XXX hackety hack... */ #ifdef __MIPSEB__ - __put_user(kbuf.f_fsid.val[1], &buf->f_fsid); + error |= __put_user(kbuf.f_fsid.val[1], &buf->f_fsid); #else - __put_user(kbuf.f_fsid.val[0], &buf->f_fsid); + error |= __put_user(kbuf.f_fsid.val[0], &buf->f_fsid); #endif for(i = 0; i < 16; i++) - __put_user(0, &buf->f_basetype[i]); - __put_user(0, &buf->f_flag); - __put_user(kbuf.f_namelen, &buf->f_namemax); + error |= __put_user(0, &buf->f_basetype[i]); + error |= __put_user(0, &buf->f_flag); + error |= __put_user(kbuf.f_namelen, &buf->f_namemax); for(i = 0; i < 32; i++) - __put_user(0, &buf->f_fstr[i]); - - error = 0; + error |= __put_user(0, &buf->f_fstr[i]); dput_and_out: path_release(&nd); @@ -1679,7 +1660,7 @@ out: return error; } -asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf) +asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs __user *buf) { struct kstatfs kbuf; struct file *file; @@ -1700,24 +1681,24 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf) if (error) goto out_f; - __put_user(kbuf.f_bsize, &buf->f_bsize); - __put_user(kbuf.f_frsize, &buf->f_frsize); - __put_user(kbuf.f_blocks, &buf->f_blocks); - __put_user(kbuf.f_bfree, &buf->f_bfree); - __put_user(kbuf.f_bfree, &buf->f_bavail); /* XXX hackety hack... */ - __put_user(kbuf.f_files, &buf->f_files); - __put_user(kbuf.f_ffree, &buf->f_ffree); - __put_user(kbuf.f_ffree, &buf->f_favail); /* XXX hackety hack... */ + error = __put_user(kbuf.f_bsize, &buf->f_bsize); + error |= __put_user(kbuf.f_frsize, &buf->f_frsize); + error |= __put_user(kbuf.f_blocks, &buf->f_blocks); + error |= __put_user(kbuf.f_bfree, &buf->f_bfree); + error |= __put_user(kbuf.f_bfree, &buf->f_bavail); /* XXX hackety hack... */ + error |= __put_user(kbuf.f_files, &buf->f_files); + error |= __put_user(kbuf.f_ffree, &buf->f_ffree); + error |= __put_user(kbuf.f_ffree, &buf->f_favail); /* XXX hackety hack... */ #ifdef __MIPSEB__ - __put_user(kbuf.f_fsid.val[1], &buf->f_fsid); + error |= __put_user(kbuf.f_fsid.val[1], &buf->f_fsid); #else - __put_user(kbuf.f_fsid.val[0], &buf->f_fsid); + error |= __put_user(kbuf.f_fsid.val[0], &buf->f_fsid); #endif for(i = 0; i < 16; i++) - __put_user(0, &buf->f_basetype[i]); - __put_user(0, &buf->f_flag); - __put_user(kbuf.f_namelen, &buf->f_namemax); - __clear_user(buf->f_fstr, sizeof(buf->f_fstr[i])); + error |= __put_user(0, &buf->f_basetype[i]); + error |= __put_user(0, &buf->f_flag); + error |= __put_user(kbuf.f_namelen, &buf->f_namemax); + error |= __clear_user(buf->f_fstr, sizeof(buf->f_fstr[i])) ? -EFAULT : 0; out_f: fput(file); @@ -1725,9 +1706,9 @@ out: return error; } -asmlinkage int irix_getmountid(char *fname, unsigned long *midbuf) +asmlinkage int irix_getmountid(char __user *fname, unsigned long __user *midbuf) { - int err = 0; + int err; printk("[%s:%d] irix_getmountid(%s, %p)\n", current->comm, current->pid, fname, midbuf); @@ -1740,7 +1721,7 @@ asmlinkage int irix_getmountid(char *fname, unsigned long *midbuf) * fsid of the filesystem to try and make the right decision, but * we don't have this so for now. XXX */ - err |= __put_user(0, &midbuf[0]); + err = __put_user(0, &midbuf[0]); err |= __put_user(0, &midbuf[1]); err |= __put_user(0, &midbuf[2]); err |= __put_user(0, &midbuf[3]); @@ -1767,8 +1748,8 @@ struct irix_dirent32 { }; struct irix_dirent32_callback { - struct irix_dirent32 *current_dir; - struct irix_dirent32 *previous; + struct irix_dirent32 __user *current_dir; + struct irix_dirent32 __user *previous; int count; int error; }; @@ -1776,13 +1757,13 @@ struct irix_dirent32_callback { #define NAME_OFFSET32(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) -static int irix_filldir32(void *__buf, const char *name, int namlen, - loff_t offset, ino_t ino, unsigned int d_type) +static int irix_filldir32(void *__buf, const char *name, + int namlen, loff_t offset, ino_t ino, unsigned int d_type) { - struct irix_dirent32 *dirent; - struct irix_dirent32_callback *buf = - (struct irix_dirent32_callback *)__buf; + struct irix_dirent32 __user *dirent; + struct irix_dirent32_callback *buf = __buf; unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1); + int err = 0; #ifdef DEBUG_GETDENTS printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]", @@ -1793,25 +1774,26 @@ static int irix_filldir32(void *__buf, const char *name, int namlen, return -EINVAL; dirent = buf->previous; if (dirent) - __put_user(offset, &dirent->d_off); + err = __put_user(offset, &dirent->d_off); dirent = buf->current_dir; - buf->previous = dirent; - __put_user(ino, &dirent->d_ino); - __put_user(reclen, &dirent->d_reclen); - copy_to_user(dirent->d_name, name, namlen); - __put_user(0, &dirent->d_name[namlen]); - ((char *) dirent) += reclen; + err |= __put_user(dirent, &buf->previous); + err |= __put_user(ino, &dirent->d_ino); + err |= __put_user(reclen, &dirent->d_reclen); + err |= copy_to_user((char __user *)dirent->d_name, name, namlen) ? -EFAULT : 0; + err |= __put_user(0, &dirent->d_name[namlen]); + dirent = (struct irix_dirent32 __user *) ((char __user *) dirent + reclen); + buf->current_dir = dirent; buf->count -= reclen; - return 0; + return err; } -asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, - unsigned int count, int *eob) +asmlinkage int irix_ngetdents(unsigned int fd, void __user * dirent, + unsigned int count, int __user *eob) { struct file *file; - struct irix_dirent32 *lastdirent; + struct irix_dirent32 __user *lastdirent; struct irix_dirent32_callback buf; int error; @@ -1824,7 +1806,7 @@ asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, if (!file) goto out; - buf.current_dir = (struct irix_dirent32 *) dirent; + buf.current_dir = (struct irix_dirent32 __user *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; @@ -1864,8 +1846,8 @@ struct irix_dirent64 { }; struct irix_dirent64_callback { - struct irix_dirent64 *curr; - struct irix_dirent64 *previous; + struct irix_dirent64 __user *curr; + struct irix_dirent64 __user *previous; int count; int error; }; @@ -1873,37 +1855,44 @@ struct irix_dirent64_callback { #define NAME_OFFSET64(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) -static int irix_filldir64(void * __buf, const char * name, int namlen, - loff_t offset, ino_t ino, unsigned int d_type) +static int irix_filldir64(void *__buf, const char *name, + int namlen, loff_t offset, ino_t ino, unsigned int d_type) { - struct irix_dirent64 *dirent; - struct irix_dirent64_callback * buf = - (struct irix_dirent64_callback *) __buf; + struct irix_dirent64 __user *dirent; + struct irix_dirent64_callback * buf = __buf; unsigned short reclen = ROUND_UP64(NAME_OFFSET64(dirent) + namlen + 1); + int err = 0; - buf->error = -EINVAL; /* only used if we fail.. */ + if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf))) + return -EFAULT; + + if (__put_user(-EINVAL, &buf->error)) /* only used if we fail.. */ + return -EFAULT; if (reclen > buf->count) return -EINVAL; dirent = buf->previous; if (dirent) - __put_user(offset, &dirent->d_off); + err = __put_user(offset, &dirent->d_off); dirent = buf->curr; buf->previous = dirent; - __put_user(ino, &dirent->d_ino); - __put_user(reclen, &dirent->d_reclen); - __copy_to_user(dirent->d_name, name, namlen); - __put_user(0, &dirent->d_name[namlen]); - ((char *) dirent) += reclen; + err |= __put_user(ino, &dirent->d_ino); + err |= __put_user(reclen, &dirent->d_reclen); + err |= __copy_to_user((char __user *)dirent->d_name, name, namlen) + ? -EFAULT : 0; + err |= __put_user(0, &dirent->d_name[namlen]); + + dirent = (struct irix_dirent64 __user *) ((char __user *) dirent + reclen); + buf->curr = dirent; buf->count -= reclen; - return 0; + return err; } -asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) +asmlinkage int irix_getdents64(int fd, void __user *dirent, int cnt) { struct file *file; - struct irix_dirent64 *lastdirent; + struct irix_dirent64 __user *lastdirent; struct irix_dirent64_callback buf; int error; @@ -1923,7 +1912,7 @@ asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) if (cnt < (sizeof(struct irix_dirent64) + 255)) goto out_f; - buf.curr = (struct irix_dirent64 *) dirent; + buf.curr = (struct irix_dirent64 __user *) dirent; buf.previous = NULL; buf.count = cnt; buf.error = 0; @@ -1935,7 +1924,8 @@ asmlinkage int irix_getdents64(int fd, void *dirent, int cnt) error = buf.error; goto out_f; } - lastdirent->d_off = (u64) file->f_pos; + if (put_user(file->f_pos, &lastdirent->d_off)) + return -EFAULT; #ifdef DEBUG_GETDENTS printk("returning %d\n", cnt - buf.count); #endif @@ -1947,10 +1937,10 @@ out: return error; } -asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) +asmlinkage int irix_ngetdents64(int fd, void __user *dirent, int cnt, int *eob) { struct file *file; - struct irix_dirent64 *lastdirent; + struct irix_dirent64 __user *lastdirent; struct irix_dirent64_callback buf; int error; @@ -1972,7 +1962,7 @@ asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) goto out_f; *eob = 0; - buf.curr = (struct irix_dirent64 *) dirent; + buf.curr = (struct irix_dirent64 __user *) dirent; buf.previous = NULL; buf.count = cnt; buf.error = 0; @@ -1984,7 +1974,8 @@ asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob) error = buf.error; goto out_f; } - lastdirent->d_off = (u64) file->f_pos; + if (put_user(file->f_pos, &lastdirent->d_off)) + return -EFAULT; #ifdef DEBUG_GETDENTS printk("eob=%d returning %d\n", *eob, cnt - buf.count); #endif @@ -2047,14 +2038,14 @@ out: return retval; } -asmlinkage int irix_utssys(char *inbuf, int arg, int type, char *outbuf) +asmlinkage int irix_utssys(char __user *inbuf, int arg, int type, char __user *outbuf) { int retval; switch(type) { case 0: /* uname() */ - retval = irix_uname((struct iuname *)inbuf); + retval = irix_uname((struct iuname __user *)inbuf); goto out; case 2: diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index d06db5f8115..f9a6a566555 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -339,9 +339,9 @@ asmlinkage void do_be(struct pt_regs *regs) static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) { - unsigned int *epc; + unsigned int __user *epc; - epc = (unsigned int *) regs->cp0_epc + + epc = (unsigned int __user *) regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) != 0); if (!get_user(*opcode, epc)) return 0; @@ -371,7 +371,7 @@ static struct task_struct *ll_task = NULL; static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode) { - unsigned long value, *vaddr; + unsigned long value, __user *vaddr; long offset; int signal = 0; @@ -385,7 +385,8 @@ static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode) offset <<= 16; offset >>= 16; - vaddr = (unsigned long *)((long)(regs->regs[(opcode & BASE) >> 21]) + offset); + vaddr = (unsigned long __user *) + ((unsigned long)(regs->regs[(opcode & BASE) >> 21]) + offset); if ((unsigned long)vaddr & 3) { signal = SIGBUS; @@ -418,7 +419,8 @@ sig: static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode) { - unsigned long *vaddr, reg; + unsigned long __user *vaddr; + unsigned long reg; long offset; int signal = 0; @@ -432,7 +434,8 @@ static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode) offset <<= 16; offset >>= 16; - vaddr = (unsigned long *)((long)(regs->regs[(opcode & BASE) >> 21]) + offset); + vaddr = (unsigned long __user *) + ((unsigned long)(regs->regs[(opcode & BASE) >> 21]) + offset); reg = (opcode & RT) >> 16; if ((unsigned long)vaddr & 3) { @@ -498,7 +501,7 @@ asmlinkage void do_ov(struct pt_regs *regs) info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)regs->cp0_epc; + info.si_addr = (void __user *) regs->cp0_epc; force_sig_info(SIGFPE, &info, current); } @@ -584,7 +587,7 @@ asmlinkage void do_bp(struct pt_regs *regs) info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)regs->cp0_epc; + info.si_addr = (void __user *) regs->cp0_epc; force_sig_info(SIGFPE, &info, current); break; default: @@ -621,7 +624,7 @@ asmlinkage void do_tr(struct pt_regs *regs) info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; info.si_errno = 0; - info.si_addr = (void *)regs->cp0_epc; + info.si_addr = (void __user *) regs->cp0_epc; force_sig_info(SIGFPE, &info, current); break; default: diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 36c5212e092..5b5a3736cbb 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -94,7 +94,7 @@ unsigned long unaligned_instructions; #endif static inline int emulate_load_store_insn(struct pt_regs *regs, - void *addr, unsigned long pc, + void __user *addr, unsigned int __user *pc, unsigned long **regptr, unsigned long *newvalue) { union mips_instruction insn; @@ -107,7 +107,7 @@ static inline int emulate_load_store_insn(struct pt_regs *regs, /* * This load never faults. */ - __get_user(insn.word, (unsigned int *)pc); + __get_user(insn.word, pc); switch (insn.i_format.opcode) { /* @@ -494,8 +494,8 @@ asmlinkage void do_ade(struct pt_regs *regs) { unsigned long *regptr, newval; extern int do_dsemulret(struct pt_regs *); + unsigned int __user *pc; mm_segment_t seg; - unsigned long pc; /* * Address errors may be deliberately induced by the FPU emulator to @@ -515,7 +515,7 @@ asmlinkage void do_ade(struct pt_regs *regs) if ((regs->cp0_badvaddr == regs->cp0_epc) || (regs->cp0_epc & 0x1)) goto sigbus; - pc = exception_epc(regs); + pc = (unsigned int __user *) exception_epc(regs); if ((current->thread.mflags & MF_FIXADE) == 0) goto sigbus; @@ -526,7 +526,7 @@ asmlinkage void do_ade(struct pt_regs *regs) seg = get_fs(); if (!user_mode(regs)) set_fs(KERNEL_DS); - if (!emulate_load_store_insn(regs, (void *)regs->cp0_badvaddr, pc, + if (!emulate_load_store_insn(regs, (void __user *)regs->cp0_badvaddr, pc, ®ptr, &newval)) { compute_return_epc(regs); /* -- cgit v1.2.3 From cdaed73afb61913ee5115aa38b0c35ecb0513f50 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 4 Mar 2005 12:35:42 +0000 Subject: Fix preemption bug. Signed-off-by: Ralf Baechle --- arch/mips/kernel/entry.S | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index ebc1a5d4f8b..6e01b0dd031 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -58,9 +58,8 @@ need_resched: LONG_L t0, PT_STATUS(sp) # Interrupts off? andi t0, 1 beqz t0, restore_all - li t0, PREEMPT_ACTIVE - sw t0, TI_PRE_COUNT($28) jal preempt_schedule_irq + b need_resched #endif FEXPORT(ret_from_fork) -- cgit v1.2.3 From 77c728c2240a1eb45f7d355f5d87ecc319cd55ce Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 4 Mar 2005 19:36:51 +0000 Subject: Gcc 4.0 fixes. Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal32.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 18c028ba9ef..663fa547ee1 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -261,11 +261,12 @@ asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, if (act) { old_sigset_t mask; + s32 handler; if (!access_ok(VERIFY_READ, act, sizeof(*act))) return -EFAULT; - err |= __get_user((u32)(u64)new_ka.sa.sa_handler, - &act->sa_handler); + err |= __get_user(handler, &act->sa_handler); + new_ka.sa.sa_handler = (void*)(s64)handler; err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); err |= __get_user(mask, &act->sa_mask.sig[0]); if (err) @@ -826,12 +827,13 @@ asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 *act, goto out; if (act) { + s32 handler; int err = 0; if (!access_ok(VERIFY_READ, act, sizeof(*act))) return -EFAULT; - err |= __get_user((u32)(u64)new_sa.sa.sa_handler, - &act->sa_handler); + err |= __get_user(handler, &act->sa_handler); + new_sa.sa.sa_handler = (void*)(s64)handler; err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags); err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask); if (err) -- cgit v1.2.3 From 9ff77c469ed16221c6a4e882e48e4f0dcf451bda Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 8 Mar 2005 14:39:39 +0000 Subject: Export shm_align_mask and flush_data_cache_page. Signed-off-by: Ralf Baechle --- arch/mips/kernel/syscall.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 21e3e13a4b4..8fde242596f 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,8 @@ out: unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ +EXPORT_SYMBOL(shm_align_mask); + #define COLOUR_ALIGN(addr,pgoff) \ ((((addr) + shm_align_mask) & ~shm_align_mask) + \ (((pgoff) << PAGE_SHIFT) & shm_align_mask)) -- cgit v1.2.3 From 90a67b5909ed39425fd2402b2b4c46ef1372b300 Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Sun, 13 Mar 2005 00:07:00 +0000 Subject: sys_futex has 6 arguments. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall32-o32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 00e4a5ed1d8..9c4bb917d47 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -578,7 +578,7 @@ einval: li v0, -EINVAL sys sys_fremovexattr 2 /* 4235 */ sys sys_tkill 2 sys sys_sendfile64 5 - sys sys_futex 2 + sys sys_futex 6 sys sys_sched_setaffinity 3 sys sys_sched_getaffinity 3 /* 4240 */ sys sys_io_setup 2 -- cgit v1.2.3 From 71e0e556db08cc20de76d510be5600f6e5ce143c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 14 Mar 2005 10:16:59 +0000 Subject: Multithreaded core dumps. Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 5223c4450e4..2b7a44deb85 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -167,6 +167,14 @@ void dump_regs(elf_greg_t *gp, struct pt_regs *regs) #endif } +int dump_task_regs (struct task_struct *tsk, elf_gregset_t *regs) +{ + struct thread_info *ti = tsk->thread_info; + long ksp = (unsigned long)ti + THREAD_SIZE - 32; + dump_regs(&(*regs)[0], (struct pt_regs *) ksp - 1); + return 1; +} + int dump_task_fpu (struct task_struct *t, elf_fpregset_t *fpr) { memcpy(fpr, &t->thread.fpu, sizeof(current->thread.fpu)); -- cgit v1.2.3 From b4dbf95e3080cf43a27cc324bfa0975f88174d07 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 16 Mar 2005 10:23:31 +0000 Subject: Get rid of the the remains of 2.4-style ramdisk support. Signed-off-by: Ralf Baechle --- arch/mips/kernel/vmlinux.lds.S | 7 ------- 1 file changed, 7 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index ff345f2c42c..25cc856d8e7 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -54,13 +54,6 @@ SECTIONS *(.data) - /* Align the initial ramdisk image (INITRD) on page boundaries. */ - . = ALIGN(4096); - __rd_start = .; - *(.initrd) - . = ALIGN(4096); - __rd_end = .; - CONSTRUCTORS } _gp = . + 0x8000; -- cgit v1.2.3 From 1592dac2410511d24836e18d416b1d02c678322b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 17 Mar 2005 21:50:49 +0000 Subject: Reformatting, remove debugging code. Signed-off-by: Ralf Baechle --- arch/mips/kernel/irixioctl.c | 63 ++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 37 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c index 3cdc22346f4..e2863821a3d 100644 --- a/arch/mips/kernel/irixioctl.c +++ b/arch/mips/kernel/irixioctl.c @@ -59,7 +59,7 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) { struct tty_struct *tp, *rtp; mm_segment_t old_fs; - int error = 0; + int i, error = 0; #ifdef DEBUG_IOCTLS printk("[%s:%d] irix_ioctl(%d, ", current->comm, current->pid, fd); @@ -74,12 +74,13 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) case 0x0000540d: { struct termios kt; - struct irix_termios *it = (struct irix_termios *) arg; + struct irix_termios __user *it = + (struct irix_termios __user *) arg; #ifdef DEBUG_IOCTLS printk("TCGETS, %08lx) ", arg); #endif - if(!access_ok(VERIFY_WRITE, it, sizeof(*it))) { + if (!access_ok(VERIFY_WRITE, it, sizeof(*it))) { error = -EFAULT; break; } @@ -88,13 +89,14 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) set_fs(old_fs); if (error) break; - __put_user(kt.c_iflag, &it->c_iflag); - __put_user(kt.c_oflag, &it->c_oflag); - __put_user(kt.c_cflag, &it->c_cflag); - __put_user(kt.c_lflag, &it->c_lflag); - for(error = 0; error < NCCS; error++) - __put_user(kt.c_cc[error], &it->c_cc[error]); - error = 0; + + error = __put_user(kt.c_iflag, &it->c_iflag); + error |= __put_user(kt.c_oflag, &it->c_oflag); + error |= __put_user(kt.c_cflag, &it->c_cflag); + error |= __put_user(kt.c_lflag, &it->c_lflag); + + for (i = 0; i < NCCS; i++) + error |= __put_user(kt.c_cc[i], &it->c_cc[i]); break; } @@ -112,14 +114,19 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) old_fs = get_fs(); set_fs(get_ds()); error = sys_ioctl(fd, TCGETS, (unsigned long) &kt); set_fs(old_fs); - if(error) + if (error) + break; + + error = __get_user(kt.c_iflag, &it->c_iflag); + error |= __get_user(kt.c_oflag, &it->c_oflag); + error |= __get_user(kt.c_cflag, &it->c_cflag); + error |= __get_user(kt.c_lflag, &it->c_lflag); + + for (i = 0; i < NCCS; i++) + error |= __get_user(kt.c_cc[i], &it->c_cc[i]); + + if (error) break; - __get_user(kt.c_iflag, &it->c_iflag); - __get_user(kt.c_oflag, &it->c_oflag); - __get_user(kt.c_cflag, &it->c_cflag); - __get_user(kt.c_lflag, &it->c_lflag); - for(error = 0; error < NCCS; error++) - __get_user(kt.c_cc[error], &it->c_cc[error]); old_fs = get_fs(); set_fs(get_ds()); error = sys_ioctl(fd, TCSETS, (unsigned long) &kt); set_fs(old_fs); @@ -153,7 +160,7 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) #ifdef DEBUG_IOCTLS printk("rtp->session=%d ", rtp->session); #endif - error = put_user(rtp->session, (unsigned long *) arg); + error = put_user(rtp->session, (unsigned long __user *) arg); break; case 0x746e: @@ -195,50 +202,32 @@ asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) break; case 0x8004667e: -#ifdef DEBUG_IOCTLS - printk("FIONBIO, %08lx) arg=%d ", arg, *(int *)arg); -#endif error = sys_ioctl(fd, FIONBIO, arg); break; case 0x80047476: -#ifdef DEBUG_IOCTLS - printk("TIOCSPGRP, %08lx) arg=%d ", arg, *(int *)arg); -#endif error = sys_ioctl(fd, TIOCSPGRP, arg); break; case 0x8020690c: -#ifdef DEBUG_IOCTLS - printk("SIOCSIFADDR, %08lx) arg=%d ", arg, *(int *)arg); -#endif error = sys_ioctl(fd, SIOCSIFADDR, arg); break; case 0x80206910: -#ifdef DEBUG_IOCTLS - printk("SIOCSIFFLAGS, %08lx) arg=%d ", arg, *(int *)arg); -#endif error = sys_ioctl(fd, SIOCSIFFLAGS, arg); break; case 0xc0206911: -#ifdef DEBUG_IOCTLS - printk("SIOCGIFFLAGS, %08lx) arg=%d ", arg, *(int *)arg); -#endif error = sys_ioctl(fd, SIOCGIFFLAGS, arg); break; case 0xc020691b: -#ifdef DEBUG_IOCTLS - printk("SIOCGIFMETRIC, %08lx) arg=%d ", arg, *(int *)arg); -#endif error = sys_ioctl(fd, SIOCGIFMETRIC, arg); break; default: { #ifdef DEBUG_MISSING_IOCTL - char *msg = "Unimplemented IOCTL cmd tell linux@engr.sgi.com\n"; + char *msg = "Unimplemented IOCTL cmd tell linux-mips@linux-mips.org\n"; #ifdef DEBUG_IOCTLS printk("UNIMP_IOCTL, %08lx)\n", arg); -- cgit v1.2.3 From 209ac8ddb16f5aea115bbcfd34dab110c28b9f56 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 18 Mar 2005 17:36:42 +0000 Subject: Use compat_sigval_t in struct compat_siginfo. Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 663fa547ee1..e8c380dceb8 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -78,7 +78,7 @@ typedef struct compat_siginfo { struct { timer_t _tid; /* timer id */ int _overrun; /* overrun count */ - sigval_t32 _sigval; /* same as below */ + compat_sigval_t _sigval;/* same as below */ int _sys_private; /* not to be passed to user */ } _timer; -- cgit v1.2.3 From 1b3a6e975cbe81c5abc55e4c1b9f5b5250c5f20e Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Fri, 1 Apr 2005 14:07:13 +0000 Subject: Fix 64bit SMP TLB handler and stack frame handling, optimize 32bit SMP TLB handlers a bit, match definitions in pgtable-{32,64}.h better. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/head.S | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 124c27e908f..9f692716935 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -157,6 +157,7 @@ NESTED(kernel_entry, 16, sp) # kernel entry point LONG_S a2, fw_arg2 LONG_S a3, fw_arg3 + MTC0 zero, CP0_CONTEXT # clear context register PTR_LA $28, init_thread_union PTR_ADDIU sp, $28, _THREAD_SIZE - 32 set_saved_sp sp, t0, t1 -- cgit v1.2.3 From 494900af689a22479eb405ff1323cad673bd9208 Mon Sep 17 00:00:00 2001 From: Pete Popov Date: Thu, 7 Apr 2005 00:42:10 +0000 Subject: Remove CONFIG_PM dependency from au1x wait in cpu_probe. Additional work necessary to completely remove that config option. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 66c2a2788ff..b7c8346df3c 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -51,29 +51,25 @@ static void r4k_wait(void) ".set\tmips0"); } -/* - * The Au1xxx wait is available only if we run CONFIG_PM and - * the timer setup found we had a 32KHz counter available. - * There are still problems with functions that may call au1k_wait - * directly, but that will be discovered pretty quickly. - */ -extern void (*au1k_wait_ptr)(void); - -void au1k_wait(void) +/* The Au1xxx wait is available only if using 32khz counter or + * external timer source, but specifically not CP0 Counter. */ +static void au1k_wait(void) { -#ifdef CONFIG_PM + unsigned long addr; /* using the wait instruction makes CP0 counter unusable */ - __asm__(".set\tmips3\n\t" + __asm__("la %0,au1k_wait\n\t" + ".set mips3\n\t" + "cache 0x14,0(%0)\n\t" + "cache 0x14,32(%0)\n\t" + "sync\n\t" + "nop\n\t" "wait\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" - ".set\tmips0"); -#else - __asm__("nop\n\t" - "nop"); -#endif + ".set mips0\n\t" + : : "r" (addr)); } static inline void check_wait(void) @@ -112,21 +108,20 @@ static inline void check_wait(void) cpu_wait = r4k_wait; printk(" available.\n"); break; -#ifdef CONFIG_PM case CPU_AU1000: case CPU_AU1100: case CPU_AU1500: case CPU_AU1550: case CPU_AU1200: - if (au1k_wait_ptr != NULL) { - cpu_wait = au1k_wait_ptr; - printk(" available.\n"); - } - else { - printk(" unavailable.\n"); + { + extern int allow_au1k_wait; /* au1000/common/time.c */ + if (allow_au1k_wait) { + cpu_wait = au1k_wait; + printk(" available.\n"); + } else + printk(" unavailable.\n"); } break; -#endif default: printk(" unavailable.\n"); break; -- cgit v1.2.3 From fe359bf58414478a0ddbd65923e2f1aceedf330f Mon Sep 17 00:00:00 2001 From: Pete Popov Date: Fri, 8 Apr 2005 08:34:43 +0000 Subject: Fixed buglet with previous patch that broke non au1x builds. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index b7c8346df3c..69e5fff00ed 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -53,9 +53,10 @@ static void r4k_wait(void) /* The Au1xxx wait is available only if using 32khz counter or * external timer source, but specifically not CP0 Counter. */ +int allow_au1k_wait; static void au1k_wait(void) { - unsigned long addr; + unsigned long addr = 0; /* using the wait instruction makes CP0 counter unusable */ __asm__("la %0,au1k_wait\n\t" ".set mips3\n\t" @@ -113,14 +114,11 @@ static inline void check_wait(void) case CPU_AU1500: case CPU_AU1550: case CPU_AU1200: - { - extern int allow_au1k_wait; /* au1000/common/time.c */ - if (allow_au1k_wait) { - cpu_wait = au1k_wait; - printk(" available.\n"); - } else - printk(" unavailable.\n"); - } + if (allow_au1k_wait) { + cpu_wait = au1k_wait; + printk(" available.\n"); + } else + printk(" unavailable.\n"); break; default: printk(" unavailable.\n"); -- cgit v1.2.3 From 2b07bd0235ca51816e4e43cb6781973358553a1b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 8 Apr 2005 20:36:05 +0000 Subject: Detect the 4KEcR2 and for now detect handle it like the 4KEc. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 69e5fff00ed..ce2966e9eb5 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -456,6 +456,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c) c->cputype = CPU_4KEC; c->isa_level = MIPS_CPU_ISA_M32; break; + case PRID_IMP_4KECR2: + c->cputype = CPU_4KEC; + c->isa_level = MIPS_CPU_ISA_M32; + break; case PRID_IMP_4KSC: c->cputype = CPU_4KSC; c->isa_level = MIPS_CPU_ISA_M32; -- cgit v1.2.3 From 6dd04688520d7abe4883b2a79fa720291d76b140 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 12 Apr 2005 11:04:15 +0000 Subject: When simulating ll/sc compute the return EPC before modifying the registers. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index f9a6a566555..77f796b9975 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -408,9 +408,10 @@ static inline void simulate_ll(struct pt_regs *regs, unsigned int opcode) preempt_enable(); + compute_return_epc(regs); + regs->regs[(opcode & RT) >> 16] = value; - compute_return_epc(regs); return; sig: @@ -459,9 +460,9 @@ static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode) goto sig; } + compute_return_epc(regs); regs->regs[reg] = 1; - compute_return_epc(regs); return; sig: -- cgit v1.2.3 From 05b8042ac6d35383c2fcc171ed932426c4e09ed1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 12 Apr 2005 20:26:05 +0000 Subject: Fix one more case of computing the return EPC after the registers have already been modified. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 77f796b9975..94d9141c04c 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -447,9 +447,9 @@ static inline void simulate_sc(struct pt_regs *regs, unsigned int opcode) preempt_disable(); if (ll_bit == 0 || ll_task != current) { + compute_return_epc(regs); regs->regs[reg] = 0; preempt_enable(); - compute_return_epc(regs); return; } -- cgit v1.2.3 From 589391a0fe229573439994b3be2cc9377722cf3d Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Wed, 13 Apr 2005 09:11:22 +0000 Subject: fcntl64 needs to be wrapped for n32. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall64-n32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index e797f15bc0f..d912218259e 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -329,7 +329,7 @@ EXPORT(sysn32_call_table) PTR sys_epoll_wait PTR sys_remap_file_pages /* 6210 */ PTR sysn32_rt_sigreturn - PTR sys_fcntl + PTR compat_sys_fcntl64 PTR sys_set_tid_address PTR sys_restart_syscall PTR sys_semtimedop /* 6215 */ -- cgit v1.2.3 From f03da6e28ea2d20f1a8451869fd1c9ea9935022b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Apr 2005 13:37:32 +0000 Subject: Fix BogoMIPS display on UP and some minor cosmetical things. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 1 - arch/mips/kernel/smp.c | 1 - 2 files changed, 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index ce2966e9eb5..21ef82de8c5 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index d1828ef5ffd..25762917e82 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -226,7 +226,6 @@ void __init smp_cpus_done(unsigned int max_cpus) /* called from main before smp_init() */ void __init smp_prepare_cpus(unsigned int max_cpus) { - cpu_data[0].udelay_val = loops_per_jiffy; init_new_context(current, &init_mm); current_thread_info()->cpu = 0; smp_tune_scheduling(); -- cgit v1.2.3 From 3c37026d43c47bec4710cbda286f4a17f416f5e6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Apr 2005 17:43:59 +0000 Subject: NPTL, round one. Signed-off-by: Ralf Baechle --- arch/mips/kernel/asm-offsets.c | 1 + arch/mips/kernel/linux32.c | 27 +++++++++++++++++++++++++ arch/mips/kernel/process.c | 4 ++++ arch/mips/kernel/ptrace.c | 5 +++++ arch/mips/kernel/ptrace32.c | 5 +++++ arch/mips/kernel/scall32-o32.S | 1 + arch/mips/kernel/scall64-64.S | 1 + arch/mips/kernel/scall64-n32.S | 1 + arch/mips/kernel/scall64-o32.S | 3 ++- arch/mips/kernel/syscall.c | 31 +++++++++++++++++++++++++--- arch/mips/kernel/traps.c | 46 +++++++++++++++++++++++++++++++++++++++--- 11 files changed, 118 insertions(+), 7 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 2c11abb5a40..af69cdbdd50 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -95,6 +95,7 @@ void output_thread_info_defines(void) offset("#define TI_PRE_COUNT ", struct thread_info, preempt_count); offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit); offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block); + offset("#define TI_TP_VALUE ", struct thread_info, tp_value); constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER); constant("#define _THREAD_SIZE ", THREAD_SIZE); constant("#define _THREAD_MASK ", THREAD_MASK); diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index e8e886dd52d..330cf84d21f 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -1468,3 +1468,30 @@ sysn32_rt_sigtimedwait(const sigset_t __user *uthese, } return sys_rt_sigtimedwait(uthese, uinfo, uts, sigsetsize); } + +save_static_function(sys32_clone); +__attribute_used__ noinline static int +_sys32_clone(nabi_no_regargs struct pt_regs regs) +{ + unsigned long clone_flags; + unsigned long newsp; + int __user *parent_tidptr, *child_tidptr; + + clone_flags = regs.regs[4]; + newsp = regs.regs[5]; + if (!newsp) + newsp = regs.regs[29]; + parent_tidptr = (int *) regs.regs[6]; + + /* Use __dummy4 instead of getting it off the stack, so that + syscall() works. */ + child_tidptr = (int __user *) __dummy4; + return do_fork(clone_flags, newsp, ®s, 0, + parent_tidptr, child_tidptr); +} + +extern asmlinkage void sys_set_thread_area(u32 addr); +asmlinkage void sys32_set_thread_area(u32 addr) +{ + sys_set_thread_area(AA(addr)); +} diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 2b7a44deb85..368526af5f5 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -89,6 +89,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct thread_info *ti = p->thread_info; struct pt_regs *childregs; long childksp; + p->set_child_tid = p->clear_child_tid = NULL; childksp = (unsigned long)ti + THREAD_SIZE - 32; @@ -134,6 +135,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, childregs->cp0_status &= ~(ST0_CU2|ST0_CU1); clear_tsk_thread_flag(p, TIF_USEDFPU); + if (clone_flags & CLONE_SETTLS) + ti->tp_value = regs->regs[7]; + return 0; } diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 2c7fc7472fb..649c90dee38 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -289,6 +289,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = ptrace_detach(child, data); break; + case PTRACE_GET_THREAD_AREA: + ret = put_user(child->thread_info->tp_value, + (unsigned long __user *) data); + break; + default: ret = ptrace_request(child, request, addr, data); break; diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index a8a72c9a1cc..eb446e52590 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -268,6 +268,11 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) wake_up_process(child); break; + case PTRACE_GET_THREAD_AREA: + ret = put_user(child->thread_info->tp_value, + (unsigned int __user *) (unsigned long) data); + break; + case PTRACE_DETACH: /* detach a process that was attached. */ ret = ptrace_detach(child, data); break; diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 9c4bb917d47..6fa1112512c 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -623,6 +623,7 @@ einval: li v0, -EINVAL sys sys_add_key 5 sys sys_request_key 4 sys sys_keyctl 5 + sys sys_set_thread_area 1 .endm diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index ffb22a2068b..d11f99b0ae5 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -449,3 +449,4 @@ sys_call_table: PTR sys_add_key PTR sys_request_key /* 5240 */ PTR sys_keyctl + PTR sys_set_thread_area diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index d912218259e..ce030412efb 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -363,3 +363,4 @@ EXPORT(sysn32_call_table) PTR sys_add_key PTR sys_request_key PTR sys_keyctl /* 6245 */ + PTR sys_set_thread_area diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 1017176bdce..f49182ea73f 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -322,7 +322,7 @@ sys_call_table: PTR sys32_ipc PTR sys_fsync PTR sys32_sigreturn - PTR sys_clone /* 4120 */ + PTR sys32_clone /* 4120 */ PTR sys_setdomainname PTR sys32_newuname PTR sys_ni_syscall /* sys_modify_ldt */ @@ -485,4 +485,5 @@ sys_call_table: PTR sys_add_key /* 4280 */ PTR sys_request_key PTR sys_keyctl + PTR sys_set_thread_area .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 8fde242596f..ee98eeb65e8 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -7,6 +7,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. * Copyright (C) 2001 MIPS Technologies, Inc. */ +#include #include #include #include @@ -176,14 +177,28 @@ _sys_clone(nabi_no_regargs struct pt_regs regs) { unsigned long clone_flags; unsigned long newsp; - int *parent_tidptr, *child_tidptr; + int __user *parent_tidptr, *child_tidptr; clone_flags = regs.regs[4]; newsp = regs.regs[5]; if (!newsp) newsp = regs.regs[29]; - parent_tidptr = (int *) regs.regs[6]; - child_tidptr = (int *) regs.regs[7]; + parent_tidptr = (int __user *) regs.regs[6]; +#ifdef CONFIG_32BIT + /* We need to fetch the fifth argument off the stack. */ + child_tidptr = NULL; + if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) { + int __user *__user *usp = (int __user *__user *) regs.regs[29]; + if (regs.regs[2] == __NR_syscall) { + if (get_user (child_tidptr, &usp[5])) + return -EFAULT; + } + else if (get_user (child_tidptr, &usp[4])) + return -EFAULT; + } +#else + child_tidptr = (int __user *) regs.regs[8]; +#endif return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } @@ -245,6 +260,16 @@ asmlinkage int sys_olduname(struct oldold_utsname * name) return error; } +void sys_set_thread_area(unsigned long addr) +{ + struct thread_info *ti = current->thread_info; + + ti->tp_value = addr; + + /* If some future MIPS implementation has this register in hardware, + * we will need to update it here (and in context switches). */ +} + asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) { int tmp, len; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 94d9141c04c..15fed020215 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -360,6 +360,10 @@ static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) #define OFFSET 0x0000ffff #define LL 0xc0000000 #define SC 0xe0000000 +#define SPEC3 0x7c000000 +#define RD 0x0000f800 +#define FUNC 0x0000003f +#define RDHWR 0x0000003b /* * The ll_bit is cleared by r*_switch.S @@ -495,6 +499,37 @@ static inline int simulate_llsc(struct pt_regs *regs) return -EFAULT; /* Strange things going on ... */ } +/* + * Simulate trapping 'rdhwr' instructions to provide user accessible + * registers not implemented in hardware. The only current use of this + * is the thread area pointer. + */ +static inline int simulate_rdhwr(struct pt_regs *regs) +{ + struct thread_info *ti = current->thread_info; + unsigned int opcode; + + if (unlikely(get_insn_opcode(regs, &opcode))) + return -EFAULT; + + if (unlikely(compute_return_epc(regs))) + return -EFAULT; + + if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { + int rd = (opcode & RD) >> 11; + int rt = (opcode & RT) >> 16; + switch (rd) { + case 29: + regs->regs[rt] = ti->tp_value; + break; + default: + return -EFAULT; + } + } + + return 0; +} + asmlinkage void do_ov(struct pt_regs *regs) { siginfo_t info; @@ -641,6 +676,9 @@ asmlinkage void do_ri(struct pt_regs *regs) if (!simulate_llsc(regs)) return; + if (!simulate_rdhwr(regs)) + return; + force_sig(SIGILL, current); } @@ -654,11 +692,13 @@ asmlinkage void do_cpu(struct pt_regs *regs) switch (cpid) { case 0: - if (cpu_has_llsc) - break; + if (!cpu_has_llsc) + if (!simulate_llsc(regs)) + return; - if (!simulate_llsc(regs)) + if (!simulate_rdhwr(regs)) return; + break; case 1: -- cgit v1.2.3 From 1fcf1cc742d01f786cda619fd49450b77b09e8c5 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Apr 2005 18:18:04 +0000 Subject: We pass a kernel pointer to do_sigaltstack in sys32_sigaltstack, so we need to do the set_fs(KERNEL_DS) thing around this call. Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal32.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index e8c380dceb8..5e7d0fa0267 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -488,6 +488,7 @@ __attribute_used__ noinline static void _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe32 *frame; + mm_segment_t old_fs; sigset_t set; stack_t st; s32 sp; @@ -518,7 +519,10 @@ _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) /* It is more difficult to avoid calling this function than to call it and ignore errors. */ + old_fs = get_fs(); + set_fs (KERNEL_DS); do_sigaltstack(&st, NULL, regs.regs[29]); + set_fs (old_fs); /* * Don't let your children do this ... -- cgit v1.2.3 From cce812c99c2169f7d3157b6f7fd38cde9af9c6c6 Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Sun, 17 Apr 2005 00:04:21 +0000 Subject: Ustat needs a wrapper on n32. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall64-n32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index ce030412efb..cb671ef5e19 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -250,7 +250,7 @@ EXPORT(sysn32_call_table) PTR compat_sys_utime /* 6130 */ PTR sys_mknod PTR sys32_personality - PTR sys_ustat + PTR sys32_ustat PTR compat_sys_statfs PTR compat_sys_fstatfs /* 6135 */ PTR sys_sysfs -- cgit v1.2.3 From cd21dfcfbb5c43de54f6be795dde07397da2bc2f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 28 Apr 2005 13:39:10 +0000 Subject: Fix preemption and SMP problems in the FP emulator code. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 15fed020215..b3ecd02757c 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -551,6 +551,14 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) preempt_disable(); +#ifdef CONFIG_PREEMPT + if (!is_fpu_owner()) { + /* We might lose fpu before disabling preempt... */ + own_fpu(); + BUG_ON(!used_math()); + restore_fp(current); + } +#endif /* * Unimplemented operation exception. If we've got the full * software emulator on-board, let's use it... @@ -562,11 +570,18 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) * a bit extreme for what should be an infrequent event. */ save_fp(current); + /* Ensure 'resume' not overwrite saved fp context again. */ + lose_fpu(); + + preempt_enable(); /* Run the emulator */ sig = fpu_emulator_cop1Handler (0, regs, ¤t->thread.fpu.soft); + preempt_disable(); + + own_fpu(); /* Using the FPU again. */ /* * We can't allow the emulated instruction to leave any of * the cause bit set in $fcr31. @@ -712,6 +727,8 @@ asmlinkage void do_cpu(struct pt_regs *regs) set_used_math(); } + preempt_enable(); + if (!cpu_has_fpu) { int sig = fpu_emulator_cop1Handler(0, regs, ¤t->thread.fpu.soft); @@ -719,8 +736,6 @@ asmlinkage void do_cpu(struct pt_regs *regs) force_sig(sig, current); } - preempt_enable(); - return; case 2: -- cgit v1.2.3 From 4194318c3941fa9cfaa63dfdab9054fcae5e08d3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 5 May 2005 16:45:59 +0000 Subject: Cleanup decoding of MIPSxx config registers. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 141 ++++++++++++++++++++++++++++++------------- arch/mips/kernel/proc.c | 8 ++- 2 files changed, 105 insertions(+), 44 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 21ef82de8c5..ba2dbc266d5 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -2,9 +2,9 @@ * Processor capabilities determination functions. * * Copyright (C) xxxx the Anonymous - * Copyright (C) 2003 Maciej W. Rozycki + * Copyright (C) 2003, 2004 Maciej W. Rozycki * Copyright (C) 1994 - 2003 Ralf Baechle - * Copyright (C) 2001 MIPS Inc. + * Copyright (C) 2001, 2004 MIPS Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -415,69 +415,126 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c) } } -static inline void decode_config1(struct cpuinfo_mips *c) +static inline unsigned int decode_config0(struct cpuinfo_mips *c) { - unsigned long config0 = read_c0_config(); - unsigned long config1; + unsigned int config0; + int isa; - if ((config0 & (1 << 31)) == 0) - return; /* actually wort a panic() */ + config0 = read_c0_config(); + + if (((config0 & MIPS_CONF_MT) >> 7) == 1) + c->options |= MIPS_CPU_TLB; + isa = (config0 & MIPS_CONF_AT) >> 13; + switch (isa) { + case 0: + c->isa_level = MIPS_CPU_ISA_M32; + break; + case 2: + c->isa_level = MIPS_CPU_ISA_M64; + break; + default: + panic("Unsupported ISA type, cp0.config0.at: %d.", isa); + } + + return config0 & MIPS_CONF_M; +} + +static inline unsigned int decode_config1(struct cpuinfo_mips *c) +{ + unsigned int config1; - /* MIPS32 or MIPS64 compliant CPU. Read Config 1 register. */ - c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC | - MIPS_CPU_LLSC | MIPS_CPU_MCHECK; config1 = read_c0_config1(); - if (config1 & (1 << 3)) + + if (config1 & MIPS_CONF1_MD) + c->ases |= MIPS_ASE_MDMX; + if (config1 & MIPS_CONF1_WR) c->options |= MIPS_CPU_WATCH; - if (config1 & (1 << 2)) - c->options |= MIPS_CPU_MIPS16; - if (config1 & (1 << 1)) + if (config1 & MIPS_CONF1_CA) + c->ases |= MIPS_ASE_MIPS16; + if (config1 & MIPS_CONF1_EP) c->options |= MIPS_CPU_EJTAG; - if (config1 & 1) { + if (config1 & MIPS_CONF1_FP) { c->options |= MIPS_CPU_FPU; c->options |= MIPS_CPU_32FPR; } + if (cpu_has_tlb) + c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1; + + return config1 & MIPS_CONF_M; +} + +static inline unsigned int decode_config2(struct cpuinfo_mips *c) +{ + unsigned int config2; + + config2 = read_c0_config2(); + + if (config2 & MIPS_CONF2_SL) + c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; + + return config2 & MIPS_CONF_M; +} + +static inline unsigned int decode_config3(struct cpuinfo_mips *c) +{ + unsigned int config3; + + config3 = read_c0_config3(); + + if (config3 & MIPS_CONF3_SM) + c->ases |= MIPS_ASE_SMARTMIPS; + + return config3 & MIPS_CONF_M; +} + +static inline void decode_configs(struct cpuinfo_mips *c) +{ + /* MIPS32 or MIPS64 compliant CPU. */ + c->options = MIPS_CPU_4KEX | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC | + MIPS_CPU_LLSC | MIPS_CPU_MCHECK; + c->scache.flags = MIPS_CACHE_NOT_PRESENT; - c->tlbsize = ((config1 >> 25) & 0x3f) + 1; + /* Read Config registers. */ + if (!decode_config0(c)) + return; /* actually worth a panic() */ + if (!decode_config1(c)) + return; + if (!decode_config2(c)) + return; + if (!decode_config3(c)) + return; } static inline void cpu_probe_mips(struct cpuinfo_mips *c) { - decode_config1(c); + decode_configs(c); + if (cpu_has_tlb) + c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_4KC: c->cputype = CPU_4KC; - c->isa_level = MIPS_CPU_ISA_M32; break; case PRID_IMP_4KEC: c->cputype = CPU_4KEC; - c->isa_level = MIPS_CPU_ISA_M32; break; case PRID_IMP_4KECR2: c->cputype = CPU_4KEC; - c->isa_level = MIPS_CPU_ISA_M32; break; case PRID_IMP_4KSC: c->cputype = CPU_4KSC; - c->isa_level = MIPS_CPU_ISA_M32; break; case PRID_IMP_5KC: c->cputype = CPU_5KC; - c->isa_level = MIPS_CPU_ISA_M64; break; case PRID_IMP_20KC: c->cputype = CPU_20KC; - c->isa_level = MIPS_CPU_ISA_M64; break; case PRID_IMP_24K: c->cputype = CPU_24K; - c->isa_level = MIPS_CPU_ISA_M32; break; case PRID_IMP_25KF: c->cputype = CPU_25KF; - c->isa_level = MIPS_CPU_ISA_M64; /* Probe for L2 cache */ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; break; @@ -486,7 +543,7 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c) static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) { - decode_config1(c); + decode_configs(c); switch (c->processor_id & 0xff00) { case PRID_IMP_AU1_REV1: case PRID_IMP_AU1_REV2: @@ -510,25 +567,19 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) panic("Unknown Au Core!"); break; } - c->isa_level = MIPS_CPU_ISA_M32; break; } } static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) { - decode_config1(c); + decode_configs(c); switch (c->processor_id & 0xff00) { case PRID_IMP_SB1: c->cputype = CPU_SB1; - c->isa_level = MIPS_CPU_ISA_M64; - c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_COUNTER | MIPS_CPU_DIVEC | - MIPS_CPU_MCHECK | MIPS_CPU_EJTAG | - MIPS_CPU_WATCH | MIPS_CPU_LLSC; -#ifndef CONFIG_SB1_PASS_1_WORKAROUNDS +#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS /* FPU in pass1 is known to have issues. */ - c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR; + c->options &= ~(MIPS_CPU_FPU | MIPS_CPU_32FPR); #endif break; } @@ -536,14 +587,12 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c) { - decode_config1(c); + decode_configs(c); + if (cpu_has_tlb) + c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_SR71000: c->cputype = CPU_SR71000; - c->isa_level = MIPS_CPU_ISA_M64; - c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX | - MIPS_CPU_4KTLB | MIPS_CPU_FPU | - MIPS_CPU_COUNTER | MIPS_CPU_MCHECK; c->scache.ways = 8; c->tlbsize = 64; break; @@ -572,15 +621,21 @@ __init void cpu_probe(void) case PRID_COMP_SIBYTE: cpu_probe_sibyte(c); break; - case PRID_COMP_SANDCRAFT: cpu_probe_sandcraft(c); break; default: c->cputype = CPU_UNKNOWN; } - if (c->options & MIPS_CPU_FPU) + if (c->options & MIPS_CPU_FPU) { c->fpu_id = cpu_get_fpu_id(); + + if (c->isa_level == MIPS_CPU_ISA_M32 || + c->isa_level == MIPS_CPU_ISA_M64) { + if (c->fpu_id & MIPS_FPIR_3D) + c->ases |= MIPS_ASE_MIPS3D; + } + } } __init void cpu_report(void) diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index d1290b1ec40..cf31d3952d6 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -2,7 +2,8 @@ * linux/arch/mips/kernel/proc.c * * Copyright (C) 1995, 1996, 2001 Ralf Baechle - * Copyright (C) 2001 MIPS Technologies, Inc. + * Copyright (C) 2001, 2004 MIPS Technologies, Inc. + * Copyright (C) 2004 Maciej W. Rozycki */ #include #include @@ -118,6 +119,11 @@ static int show_cpuinfo(struct seq_file *m, void *v) cpu_has_divec ? "yes" : "no"); seq_printf(m, "hardware watchpoint\t: %s\n", cpu_has_watch ? "yes" : "no"); + seq_printf(m, "ASEs implemented\t:%s%s%s%s\n", + cpu_has_mips16 ? " mips16" : "", + cpu_has_mdmx ? " mdmx" : "", + cpu_has_mips3d ? " mips3d" : "", + cpu_has_smartmips ? " smartmips" : ""); sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", cpu_has_vce ? "%u" : "not available"); -- cgit v1.2.3 From b382fe848345fe626b74a559fa89d2d966d03b02 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 6 May 2005 14:31:13 +0000 Subject: No point in checking cpu_has_tlb before we've computed the CPU options. So for now we just unconditionally set the option - Linux wouldn't work without a TLB anyway. Setting MIPS_CPU_4KTLB was missing for Alchemy and Sandcraft, add that back. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index ba2dbc266d5..cde88285a52 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -509,8 +509,7 @@ static inline void decode_configs(struct cpuinfo_mips *c) static inline void cpu_probe_mips(struct cpuinfo_mips *c) { decode_configs(c); - if (cpu_has_tlb) - c->options |= MIPS_CPU_4KTLB; + c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_4KC: c->cputype = CPU_4KC; @@ -544,6 +543,7 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c) static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) { decode_configs(c); + c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_AU1_REV1: case PRID_IMP_AU1_REV2: @@ -574,6 +574,7 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) { decode_configs(c); + c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_SB1: c->cputype = CPU_SB1; @@ -588,8 +589,7 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c) { decode_configs(c); - if (cpu_has_tlb) - c->options |= MIPS_CPU_4KTLB; + c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_SR71000: c->cputype = CPU_SR71000; -- cgit v1.2.3 From d547c5cc2186be9d74b0c595dc8059aef56cd445 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 6 May 2005 16:28:55 +0000 Subject: sys_nfsservctl() needs translation. Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall64-o32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index f49182ea73f..deb7f932e28 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -391,7 +391,7 @@ sys_call_table: PTR sys_getresuid PTR sys_ni_syscall /* was query_module */ PTR sys_poll - PTR sys_nfsservctl + PTR compat_sys_nfsservctl PTR sys_setresgid /* 4190 */ PTR sys_getresgid PTR sys_prctl -- cgit v1.2.3 From 1d74f6bc85cbdc4601e5aea1e67ccbd259f0c7f4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 9 May 2005 13:16:07 +0000 Subject: __compute_return_epc() uses CFC1 instruction which might result in a coprocessor unusable exception since the process can lose its fpu context by preemption. Signed-off-by: Ralf Baechle --- arch/mips/kernel/branch.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 01117e977a7..56aea5f526a 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -161,10 +162,13 @@ int __compute_return_epc(struct pt_regs *regs) * And now the FPA/cp1 branch instructions. */ case cop1_op: - if (!cpu_has_fpu) - fcr31 = current->thread.fpu.soft.fcr31; - else + preempt_disable(); + if (is_fpu_owner()) asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); + else + fcr31 = current->thread.fpu.hard.fcr31; + preempt_enable(); + bit = (insn.i_format.rt >> 2); bit += (bit != 0); bit += 23; -- cgit v1.2.3 From f8280c8d3d51667015c2363eeaa76b4e28e002a5 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 19 May 2005 12:08:04 +0000 Subject: Fix tasteless #ifdef mess in audit_arch(), minor cleanups. Signed-off-by: Ralf Baechle --- arch/mips/kernel/ptrace.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 649c90dee38..49821ee1898 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -308,21 +309,14 @@ out: static inline int audit_arch(void) { -#ifdef CONFIG_CPU_LITTLE_ENDIAN + int arch = EM_MIPS; #ifdef CONFIG_64BIT - if (!(current->thread.mflags & MF_32BIT_REGS)) - return AUDIT_ARCH_MIPSEL64; -#endif /* MIPS64 */ - return AUDIT_ARCH_MIPSEL; - -#else /* big endian... */ -#ifdef CONFIG_64BIT - if (!(current->thread.mflags & MF_32BIT_REGS)) - return AUDIT_ARCH_MIPS64; -#endif /* MIPS64 */ - return AUDIT_ARCH_MIPS; - -#endif /* endian */ + arch |= __AUDIT_ARCH_64BIT; +#endif +#if defined(__LITTLE_ENDIAN) + arch |= __AUDIT_ARCH_LE; +#endif + return arch; } /* @@ -332,12 +326,13 @@ static inline int audit_arch(void) asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) { if (unlikely(current->audit_context) && entryexit) - audit_syscall_exit(current, AUDITSC_RESULT(regs->regs[2]), regs->regs[2]); + audit_syscall_exit(current, AUDITSC_RESULT(regs->regs[2]), + regs->regs[2]); - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - goto out; if (!(current->ptrace & PT_PTRACED)) goto out; + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + goto out; /* The 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ -- cgit v1.2.3 From 10f650db1bcc193ea07d4f8c2f07315da38ea0c4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 25 May 2005 13:32:49 +0000 Subject: 64-bit fixes for Alchemy code ;) Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index cde88285a52..552d2b6c191 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -53,14 +53,13 @@ static void r4k_wait(void) /* The Au1xxx wait is available only if using 32khz counter or * external timer source, but specifically not CP0 Counter. */ int allow_au1k_wait; + static void au1k_wait(void) { - unsigned long addr = 0; /* using the wait instruction makes CP0 counter unusable */ - __asm__("la %0,au1k_wait\n\t" - ".set mips3\n\t" - "cache 0x14,0(%0)\n\t" - "cache 0x14,32(%0)\n\t" + __asm__(".set mips3\n\t" + "cache 0x14, 0(%0)\n\t" + "cache 0x14, 32(%0)\n\t" "sync\n\t" "nop\n\t" "wait\n\t" @@ -69,7 +68,7 @@ static void au1k_wait(void) "nop\n\t" "nop\n\t" ".set mips0\n\t" - : : "r" (addr)); + : : "r" (au1k_wait)); } static inline void check_wait(void) -- cgit v1.2.3 From e50c0a8fa60da9ac0e0a70caa8a3a803815c1f2f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 31 May 2005 11:49:19 +0000 Subject: Support the MIPS32 / MIPS64 DSP ASE. Signed-off-by: Ralf Baechle --- arch/mips/kernel/asm-offsets.c | 26 +++++++++++++++--- arch/mips/kernel/branch.c | 19 ++++++++++++- arch/mips/kernel/cpu-probe.c | 3 +++ arch/mips/kernel/genex.S | 1 + arch/mips/kernel/process.c | 58 ++++++++++++++++++++++++++++++++++++++-- arch/mips/kernel/ptrace.c | 38 ++++++++++++++++++++++++++ arch/mips/kernel/ptrace32.c | 38 ++++++++++++++++++++++++++ arch/mips/kernel/r4k_fpu.S | 5 +--- arch/mips/kernel/scall32-o32.S | 2 +- arch/mips/kernel/setup.c | 9 +++++++ arch/mips/kernel/signal-common.h | 56 +++++++++++++++++++++++++++++++++++--- arch/mips/kernel/signal.c | 52 +++++++---------------------------- arch/mips/kernel/signal32.c | 34 ++++++++++++++++------- arch/mips/kernel/traps.c | 49 ++++++++++++++++++++++----------- 14 files changed, 308 insertions(+), 82 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index af69cdbdd50..ca6b03c773b 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -95,7 +95,7 @@ void output_thread_info_defines(void) offset("#define TI_PRE_COUNT ", struct thread_info, preempt_count); offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit); offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block); - offset("#define TI_TP_VALUE ", struct thread_info, tp_value); + offset("#define TI_TP_VALUE ", struct thread_info, tp_value); constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER); constant("#define _THREAD_SIZE ", THREAD_SIZE); constant("#define _THREAD_MASK ", THREAD_MASK); @@ -241,6 +241,7 @@ void output_mm_defines(void) linefeed; } +#ifdef CONFIG_32BIT void output_sc_defines(void) { text("/* Linux sigcontext offsets. */"); @@ -252,10 +253,29 @@ void output_sc_defines(void) offset("#define SC_STATUS ", struct sigcontext, sc_status); offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir); - offset("#define SC_CAUSE ", struct sigcontext, sc_cause); - offset("#define SC_BADVADDR ", struct sigcontext, sc_badvaddr); + offset("#define SC_HI1 ", struct sigcontext, sc_hi1); + offset("#define SC_LO1 ", struct sigcontext, sc_lo1); + offset("#define SC_HI2 ", struct sigcontext, sc_hi2); + offset("#define SC_LO2 ", struct sigcontext, sc_lo2); + offset("#define SC_HI3 ", struct sigcontext, sc_hi3); + offset("#define SC_LO3 ", struct sigcontext, sc_lo3); linefeed; } +#endif + +#ifdef CONFIG_64BIT +void output_sc_defines(void) +{ + text("/* Linux sigcontext offsets. */"); + offset("#define SC_REGS ", struct sigcontext, sc_regs); + offset("#define SC_FPREGS ", struct sigcontext, sc_fpregs); + offset("#define SC_MDHI ", struct sigcontext, sc_hi); + offset("#define SC_MDLO ", struct sigcontext, sc_lo); + offset("#define SC_PC ", struct sigcontext, sc_pc); + offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); + linefeed; +} +#endif #ifdef CONFIG_MIPS32_COMPAT void output_sc32_defines(void) diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 56aea5f526a..374de839558 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -22,7 +22,7 @@ */ int __compute_return_epc(struct pt_regs *regs) { - unsigned int *addr, bit, fcr31; + unsigned int *addr, bit, fcr31, dspcontrol; long epc; union mips_instruction insn; @@ -99,6 +99,18 @@ int __compute_return_epc(struct pt_regs *regs) epc += 8; regs->cp0_epc = epc; break; + case bposge32_op: + if (!cpu_has_dsp) + goto sigill; + + dspcontrol = rddsp(0x01); + + if (dspcontrol >= 32) { + epc = epc + 4 + (insn.i_format.simmediate << 2); + } else + epc += 8; + regs->cp0_epc = epc; + break; } break; @@ -200,4 +212,9 @@ unaligned: printk("%s: unaligned epc - sending SIGBUS.\n", current->comm); force_sig(SIGBUS, current); return -EFAULT; + +sigill: + printk("%s: DSP branch but not DSP ASE - sending SIGBUS.\n", current->comm); + force_sig(SIGBUS, current); + return -EFAULT; } diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 552d2b6c191..1ae7762fd08 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -482,6 +482,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) if (config3 & MIPS_CONF3_SM) c->ases |= MIPS_ASE_SMARTMIPS; + if (config3 & MIPS_CONF3_DSP) + c->ases |= MIPS_ASE_DSP; return config3 & MIPS_CONF_M; } @@ -529,6 +531,7 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c) c->cputype = CPU_20KC; break; case PRID_IMP_24K: + case PRID_IMP_24KE: c->cputype = CPU_24K; break; case PRID_IMP_25KF: diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index e5021c758ef..349ec301168 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -291,6 +291,7 @@ NESTED(nmi_handler, PT_SIZE, sp) BUILD_HANDLER mdmx mdmx sti silent /* #22 */ BUILD_HANDLER watch watch sti verbose /* #23 */ BUILD_HANDLER mcheck mcheck cli verbose /* #24 */ + BUILD_HANDLER dsp dsp sti silent /* #26 */ BUILD_HANDLER reserved reserved sti verbose /* others */ #ifdef CONFIG_64BIT diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 368526af5f5..98432097a86 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -25,8 +25,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -54,6 +56,54 @@ ATTRIB_NORET void cpu_idle(void) } } +extern int do_signal(sigset_t *oldset, struct pt_regs *regs); +extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); + +/* + * Native o32 and N64 ABI without DSP ASE + */ +extern void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set); +extern void setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set, siginfo_t *info); + +struct mips_abi mips_abi = { + .do_signal = do_signal, +#ifdef CONFIG_TRAD_SIGNALS + .setup_frame = setup_frame, +#endif + .setup_rt_frame = setup_rt_frame +}; + +#ifdef CONFIG_MIPS32_O32 +/* + * o32 compatibility on 64-bit kernels, without DSP ASE + */ +extern void setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set); +extern void setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set, siginfo_t *info); + +struct mips_abi mips_abi_32 = { + .do_signal = do_signal32, + .setup_frame = setup_frame_32, + .setup_rt_frame = setup_rt_frame_32 +}; +#endif /* CONFIG_MIPS32_O32 */ + +#ifdef CONFIG_MIPS32_N32 +/* + * N32 on 64-bit kernels, without DSP ASE + */ +extern void setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set, siginfo_t *info); + +struct mips_abi mips_abi_n32 = { + .do_signal = do_signal, + .setup_rt_frame = setup_rt_frame_n32 +}; +#endif /* CONFIG_MIPS32_N32 */ + asmlinkage void ret_from_fork(void); void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) @@ -70,6 +120,8 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) regs->cp0_status = status; clear_used_math(); lose_fpu(); + if (cpu_has_dsp) + __init_dsp(); regs->cp0_epc = pc; regs->regs[29] = sp; current_thread_info()->addr_limit = USER_DS; @@ -95,9 +147,11 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, preempt_disable(); - if (is_fpu_owner()) { + if (is_fpu_owner()) save_fp(p); - } + + if (cpu_has_dsp) + save_dsp(p); preempt_enable(); diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 49821ee1898..2441e32ce82 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -176,6 +177,27 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) write_c0_status(flags); break; } + case DSP_BASE ... DSP_BASE + 5: + if (!cpu_has_dsp) { + tmp = 0; + ret = -EIO; + goto out_tsk; + } + if (child->thread.dsp.used_dsp) { + dspreg_t *dregs = __get_dsp_regs(child); + tmp = (unsigned long) (dregs[addr - DSP_BASE]); + } else { + tmp = -1; /* DSP registers yet used */ + } + break; + case DSP_CONTROL: + if (!cpu_has_dsp) { + tmp = 0; + ret = -EIO; + goto out_tsk; + } + tmp = child->thread.dsp.dspcontrol; + break; default: tmp = 0; ret = -EIO; @@ -248,6 +270,22 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) else child->thread.fpu.soft.fcr31 = data; break; + case DSP_BASE ... DSP_BASE + 5: + if (!cpu_has_dsp) { + ret = -EIO; + break; + } + + dspreg_t *dregs = __get_dsp_regs(child); + dregs[addr - DSP_BASE] = data; + break; + case DSP_CONTROL: + if (!cpu_has_dsp) { + ret = -EIO; + break; + } + child->thread.dsp.dspcontrol = data; + break; default: /* The rest are not allowed. */ ret = -EIO; diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index eb446e52590..5c45a588022 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -161,6 +162,27 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) write_c0_status(flags); break; } + case DSP_BASE ... DSP_BASE + 5: + if (!cpu_has_dsp) { + tmp = 0; + ret = -EIO; + goto out_tsk; + } + if (child->thread.dsp.used_dsp) { + dspreg_t *dregs = __get_dsp_regs(child); + tmp = (unsigned long) (dregs[addr - DSP_BASE]); + } else { + tmp = -1; /* DSP registers yet used */ + } + break; + case DSP_CONTROL: + if (!cpu_has_dsp) { + tmp = 0; + ret = -EIO; + goto out_tsk; + } + tmp = child->thread.dsp.dspcontrol; + break; default: tmp = 0; ret = -EIO; @@ -230,6 +252,22 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) else child->thread.fpu.soft.fcr31 = data; break; + case DSP_BASE ... DSP_BASE + 5: + if (!cpu_has_dsp) { + ret = -EIO; + break; + } + + dspreg_t *dregs = __get_dsp_regs(child); + dregs[addr - DSP_BASE] = data; + break; + case DSP_CONTROL: + if (!cpu_has_dsp) { + ret = -EIO; + break; + } + child->thread.dsp.dspcontrol = data; + break; default: /* The rest are not allowed. */ ret = -EIO; diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 1a14c6b1882..283a98508fc 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -32,7 +32,7 @@ .set noreorder .set mips3 - /* Save floating point context */ + LEAF(_save_fp_context) cfc1 t1, fcr31 @@ -74,9 +74,6 @@ LEAF(_save_fp_context) EX sdc1 $f28, SC_FPREGS+224(a0) EX sdc1 $f30, SC_FPREGS+240(a0) EX sw t1, SC_FPC_CSR(a0) - cfc1 t0, $0 # implementation/version - EX sw t0, SC_FPC_EIR(a0) - jr ra li v0, 0 # success END(_save_fp_context) diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 6fa1112512c..c389dbaa279 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -620,7 +620,7 @@ einval: li v0, -EINVAL sys sys_ni_syscall 0 /* sys_vserver */ sys sys_waitid 5 sys sys_ni_syscall 0 /* available, was setaltroot */ - sys sys_add_key 5 + sys sys_add_key 5 /* 4280 */ sys sys_request_key 4 sys sys_keyctl 5 sys sys_set_thread_area 1 diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 6fc51b29830..9253dccefd0 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -549,3 +549,12 @@ int __init fpu_disable(char *s) } __setup("nofpu", fpu_disable); + +int __init dsp_disable(char *s) +{ + cpu_data[0].ases &= ~MIPS_ASE_DSP; + + return 1; +} + +__setup("nodsp", dsp_disable); diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index f9234df5325..3208ff528cd 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -8,13 +8,14 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ +#include + static inline int setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { int err = 0; err |= __put_user(regs->cp0_epc, &sc->sc_pc); - err |= __put_user(regs->cp0_status, &sc->sc_status); #define save_gp_reg(i) do { \ err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ @@ -30,10 +31,32 @@ setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) save_gp_reg(31); #undef save_gp_reg +#ifdef CONFIG_32BIT err |= __put_user(regs->hi, &sc->sc_mdhi); err |= __put_user(regs->lo, &sc->sc_mdlo); - err |= __put_user(regs->cp0_cause, &sc->sc_cause); - err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } +#endif +#ifdef CONFIG_64BIT + err |= __put_user(regs->hi, &sc->sc_hi[0]); + err |= __put_user(regs->lo, &sc->sc_lo[0]); + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi[1]); + err |= __put_user(mflo1(), &sc->sc_lo[1]); + err |= __put_user(mfhi2(), &sc->sc_hi[2]); + err |= __put_user(mflo2(), &sc->sc_lo[2]); + err |= __put_user(mfhi3(), &sc->sc_hi[3]); + err |= __put_user(mflo3(), &sc->sc_lo[3]); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } +#endif err |= __put_user(!!used_math(), &sc->sc_used_math); @@ -61,15 +84,40 @@ out: static inline int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { - int err = 0; unsigned int used_math; + unsigned long treg; + int err = 0; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; err |= __get_user(regs->cp0_epc, &sc->sc_pc); +#ifdef CONFIG_32BIT err |= __get_user(regs->hi, &sc->sc_mdhi); err |= __get_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } +#endif +#ifdef CONFIG_64BIT + err |= __get_user(regs->hi, &sc->sc_hi[0]); + err |= __get_user(regs->lo, &sc->sc_lo[0]); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg); + err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg); + err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } +#endif #define restore_gp_reg(i) do { \ err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index eb127230cc9..8504febf8b2 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -36,7 +37,7 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -static int do_signal(sigset_t *oldset, struct pt_regs *regs); +int do_signal(sigset_t *oldset, struct pt_regs *regs); /* * Atomically swap in the new signal mask, and wait for a signal. @@ -216,7 +217,7 @@ _sys_sigreturn(nabi_no_regargs struct pt_regs regs) badframe: force_sig(SIGSEGV, current); } -#endif +#endif /* CONFIG_TRAD_SIGNALS */ save_static_function(sys_rt_sigreturn); __attribute_used__ noinline static void @@ -262,7 +263,7 @@ badframe: } #ifdef CONFIG_TRAD_SIGNALS -static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs, +void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set) { struct sigframe *frame; @@ -318,7 +319,7 @@ give_sigsegv: } #endif -static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, +void setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info) { struct rt_sigframe *frame; @@ -410,22 +411,10 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, regs->regs[0] = 0; /* Don't deal with this again. */ -#ifdef CONFIG_TRAD_SIGNALS - if (ka->sa.sa_flags & SA_SIGINFO) { -#else - if (1) { -#endif -#ifdef CONFIG_MIPS32_N32 - if ((current->thread.mflags & MF_ABI_MASK) == MF_N32) - setup_rt_frame_n32 (ka, regs, sig, oldset, info); - else -#endif - setup_rt_frame(ka, regs, sig, oldset, info); - } -#ifdef CONFIG_TRAD_SIGNALS + if (sig_uses_siginfo(ka)) + current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); else - setup_frame(ka, regs, sig, oldset); -#endif + current->thread.abi->setup_frame(ka, regs, sig, oldset); spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -435,21 +424,12 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, spin_unlock_irq(¤t->sighand->siglock); } -extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); -extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs); - -static int do_signal(sigset_t *oldset, struct pt_regs *regs) +int do_signal(sigset_t *oldset, struct pt_regs *regs) { struct k_sigaction ka; siginfo_t info; int signr; -#ifdef CONFIG_BINFMT_ELF32 - if ((current->thread.mflags & MF_ABI_MASK) == MF_O32) { - return do_signal32(oldset, regs); - } -#endif - /* * We want the common case to go fast, which is why we may in certain * cases get here from kernel mode. Just return without doing anything @@ -501,18 +481,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, { /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) { -#ifdef CONFIG_BINFMT_ELF32 - if (likely((current->thread.mflags & MF_ABI_MASK) == MF_O32)) { - do_signal32(oldset, regs); - return; - } -#endif -#ifdef CONFIG_BINFMT_IRIX - if (unlikely(current->personality != PER_LINUX)) { - do_irix_signal(oldset, regs); - return; - } -#endif - do_signal(oldset, regs); + current->thread.abi->do_signal(oldset, regs); } } diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 5e7d0fa0267..8639e24732a 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -334,8 +335,9 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc) { + u32 used_math; int err = 0; - __u32 used_math; + s32 treg; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; @@ -343,6 +345,15 @@ static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc) err |= __get_user(regs->cp0_epc, &sc->sc_pc); err |= __get_user(regs->hi, &sc->sc_mdhi); err |= __get_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } #define restore_gp_reg(i) do { \ err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ @@ -562,8 +573,15 @@ static inline int setup_sigcontext32(struct pt_regs *regs, err |= __put_user(regs->hi, &sc->sc_mdhi); err |= __put_user(regs->lo, &sc->sc_mdlo); - err |= __put_user(regs->cp0_cause, &sc->sc_cause); - err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); + if (cpu_has_dsp) { + err |= __put_user(rddsp(DSP_MASK), &sc->sc_hi1); + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + } err |= __put_user(!!used_math(), &sc->sc_used_math); @@ -613,7 +631,7 @@ static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, return (void *)((sp - frame_size) & ALMASK); } -static inline void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, +void setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set) { struct sigframe *frame; @@ -666,9 +684,7 @@ give_sigsegv: force_sigsegv(signr, current); } -static inline void setup_rt_frame(struct k_sigaction * ka, - struct pt_regs *regs, int signr, - sigset_t *set, siginfo_t *info) +void setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info) { struct rt_sigframe32 *frame; int err = 0; @@ -759,9 +775,9 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, regs->regs[0] = 0; /* Don't deal with this again. */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(ka, regs, sig, oldset, info); + current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); else - setup_frame(ka, regs, sig, oldset); + current->thread.abi->setup_frame(ka, regs, sig, oldset); spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b3ecd02757c..9419a3542c2 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ extern asmlinkage void handle_tr(void); extern asmlinkage void handle_fpe(void); extern asmlinkage void handle_mdmx(void); extern asmlinkage void handle_watch(void); +extern asmlinkage void handle_dsp(void); extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); @@ -775,6 +777,14 @@ asmlinkage void do_mcheck(struct pt_regs *regs) (regs->cp0_status & ST0_TS) ? "" : "not "); } +asmlinkage void do_dsp(struct pt_regs *regs) +{ + if (cpu_has_dsp) + panic("Unexpected DSP exception\n"); + + force_sig(SIGILL, current); +} + asmlinkage void do_reserved(struct pt_regs *regs) { /* @@ -984,9 +994,12 @@ void __init per_cpu_trap_init(void) #endif if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV) status_set |= ST0_XX; - change_c0_status(ST0_CU|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, + change_c0_status(ST0_CU|ST0_MX|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, status_set); + if (cpu_has_dsp) + set_c0_status(ST0_MX); + /* * Some MIPS CPUs have a dedicated interrupt vector which reduces the * interrupt processing overhead. Use it where available. @@ -1078,21 +1091,6 @@ void __init trap_init(void) set_except_vector(11, handle_cpu); set_except_vector(12, handle_ov); set_except_vector(13, handle_tr); - set_except_vector(22, handle_mdmx); - - if (cpu_has_fpu && !cpu_has_nofpuex) - set_except_vector(15, handle_fpe); - - if (cpu_has_mcheck) - set_except_vector(24, handle_mcheck); - - if (cpu_has_vce) - /* Special exception: R4[04]00 uses also the divec space. */ - memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100); - else if (cpu_has_4kex) - memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80); - else - memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80); if (current_cpu_data.cputype == CPU_R6000 || current_cpu_data.cputype == CPU_R6000A) { @@ -1108,6 +1106,25 @@ void __init trap_init(void) //set_except_vector(15, handle_ndc); } + if (cpu_has_fpu && !cpu_has_nofpuex) + set_except_vector(15, handle_fpe); + + set_except_vector(22, handle_mdmx); + + if (cpu_has_mcheck) + set_except_vector(24, handle_mcheck); + + if (cpu_has_dsp) + set_except_vector(26, handle_dsp); + + if (cpu_has_vce) + /* Special exception: R4[04]00 uses also the divec space. */ + memcpy((void *)(CAC_BASE + 0x180), &except_vec3_r4000, 0x100); + else if (cpu_has_4kex) + memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80); + else + memcpy((void *)(CAC_BASE + 0x080), &except_vec3_generic, 0x80); + signal_init(); #ifdef CONFIG_MIPS32_COMPAT signal32_init(); -- cgit v1.2.3 From d5b6f1db5d5a7ba3f2271e5018db7c8c5c4eeea1 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 6 Jun 2005 16:40:58 +0000 Subject: For MIPS32/MIPS64 cp0.config.mt == 1 implies a standard (R4k-style) TLB, so no need to set it separately for each implementation. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 1ae7762fd08..2b6db681417 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -422,7 +422,7 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c) config0 = read_c0_config(); if (((config0 & MIPS_CONF_MT) >> 7) == 1) - c->options |= MIPS_CPU_TLB; + c->options |= MIPS_CPU_TLB | MIPS_CPU_4KTLB; isa = (config0 & MIPS_CONF_AT) >> 13; switch (isa) { case 0: @@ -510,7 +510,6 @@ static inline void decode_configs(struct cpuinfo_mips *c) static inline void cpu_probe_mips(struct cpuinfo_mips *c) { decode_configs(c); - c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_4KC: c->cputype = CPU_4KC; @@ -545,7 +544,6 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c) static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) { decode_configs(c); - c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_AU1_REV1: case PRID_IMP_AU1_REV2: @@ -576,7 +574,6 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) { decode_configs(c); - c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_SB1: c->cputype = CPU_SB1; @@ -591,7 +588,6 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c) { decode_configs(c); - c->options |= MIPS_CPU_4KTLB; switch (c->processor_id & 0xff00) { case PRID_IMP_SR71000: c->cputype = CPU_SR71000; -- cgit v1.2.3 From aac8aa7717a23a9bf8740dbfb59755b1d62f04bf Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Tue, 14 Jun 2005 17:35:03 +0000 Subject: Enable a suitable ISA for the assembler around ll/sc so that code builds even for processors that don't support the instructions. Plus minor formatting fixes. Signed-off-by: Ralf Baechle --- arch/mips/kernel/semaphore.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/semaphore.c b/arch/mips/kernel/semaphore.c index 9c40fe5a8e8..dbb145ee00a 100644 --- a/arch/mips/kernel/semaphore.c +++ b/arch/mips/kernel/semaphore.c @@ -42,24 +42,28 @@ static inline int __sem_update_count(struct semaphore *sem, int incr) if (cpu_has_llsc && R10000_LLSC_WAR) { __asm__ __volatile__( - "1: ll %0, %2 \n" + " .set mips2 \n" + "1: ll %0, %2 # __sem_update_count \n" " sra %1, %0, 31 \n" " not %1 \n" " and %1, %0, %1 \n" - " add %1, %1, %3 \n" + " addu %1, %1, %3 \n" " sc %1, %2 \n" " beqzl %1, 1b \n" + " .set mips0 \n" : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) : "r" (incr), "m" (sem->count)); } else if (cpu_has_llsc) { __asm__ __volatile__( - "1: ll %0, %2 \n" + " .set mips2 \n" + "1: ll %0, %2 # __sem_update_count \n" " sra %1, %0, 31 \n" " not %1 \n" " and %1, %0, %1 \n" - " add %1, %1, %3 \n" + " addu %1, %1, %3 \n" " sc %1, %2 \n" " beqz %1, 1b \n" + " .set mips0 \n" : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count) : "r" (incr), "m" (sem->count)); } else { -- cgit v1.2.3 From 02416dcf5a94af34bcd28b4baf25bbbf399d8136 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 15 Jun 2005 13:00:12 +0000 Subject: Redo RM9000 workaround which along with other DSP ASE changes was causing some headache for debuggers knowing about signal frames. Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal-common.h | 34 +++++++++++++++++++---- arch/mips/kernel/signal.c | 59 ++++++++++++++++++---------------------- arch/mips/kernel/signal32.c | 16 +++++++++++ arch/mips/kernel/signal_n32.c | 32 +++++++++------------- 4 files changed, 84 insertions(+), 57 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 3208ff528cd..0f66ae5838b 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -160,7 +160,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) static inline void * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) { - unsigned long sp, almask; + unsigned long sp; /* Default to using normal stack */ sp = regs->regs[29]; @@ -176,10 +176,32 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) sp = current->sas_ss_sp + current->sas_ss_size; - if (PLAT_TRAMPOLINE_STUFF_LINE) - almask = ~(PLAT_TRAMPOLINE_STUFF_LINE - 1); - else - almask = ALMASK; + return (void *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? 32 : ALMASK)); +} + +static inline int install_sigtramp(unsigned int __user *tramp, + unsigned int syscall) +{ + int err; - return (void *)((sp - frame_size) & almask); + /* + * Set up the return code ... + * + * li v0, __NR__foo_sigreturn + * syscall + */ + + err = __put_user(0x24020000 + syscall, tramp + 0); + err |= __put_user(0x0000000c , tramp + 1); + if (ICACHE_REFILLS_WORKAROUND_WAR) { + err |= __put_user(0, tramp + 2); + err |= __put_user(0, tramp + 3); + err |= __put_user(0, tramp + 4); + err |= __put_user(0, tramp + 5); + err |= __put_user(0, tramp + 6); + err |= __put_user(0, tramp + 7); + } + flush_cache_sigtramp((unsigned long) tramp); + + return err; } diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 8504febf8b2..8679ccff870 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -8,6 +8,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #include "signal-common.h" @@ -157,26 +159,39 @@ asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs) return do_sigaltstack(uss, uoss, usp); } -#if PLAT_TRAMPOLINE_STUFF_LINE -#define __tramp __attribute__((aligned(PLAT_TRAMPOLINE_STUFF_LINE))) -#else -#define __tramp -#endif - +/* + * Horribly complicated - with the bloody RM9000 workarounds enabled + * the signal trampolines is moving to the end of the structure so we can + * increase the alignment without breaking software compatibility. + */ #ifdef CONFIG_TRAD_SIGNALS struct sigframe { u32 sf_ass[4]; /* argument save space for o32 */ - u32 sf_code[2] __tramp; /* signal trampoline */ - struct sigcontext sf_sc __tramp; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 sf_pad[2]; +#else + u32 sf_code[2]; /* signal trampoline */ +#endif + struct sigcontext sf_sc; sigset_t sf_mask; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ +#endif }; #endif struct rt_sigframe { u32 rs_ass[4]; /* argument save space for o32 */ - u32 rs_code[2] __tramp; /* signal trampoline */ - struct siginfo rs_info __tramp; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 rs_pad[2]; +#else + u32 rs_code[2]; /* signal trampoline */ +#endif + struct siginfo rs_info; struct ucontext rs_uc; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ +#endif }; #ifdef CONFIG_TRAD_SIGNALS @@ -273,17 +288,7 @@ void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - /* - * Set up the return code ... - * - * li v0, __NR_sigreturn - * syscall - */ - if (PLAT_TRAMPOLINE_STUFF_LINE) - __clear_user(frame->sf_code, PLAT_TRAMPOLINE_STUFF_LINE); - err |= __put_user(0x24020000 + __NR_sigreturn, frame->sf_code + 0); - err |= __put_user(0x0000000c , frame->sf_code + 1); - flush_cache_sigtramp((unsigned long) frame->sf_code); + install_sigtramp(frame->sf_code, __NR_sigreturn); err |= setup_sigcontext(regs, &frame->sf_sc); err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); @@ -329,17 +334,7 @@ void setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - /* - * Set up the return code ... - * - * li v0, __NR_rt_sigreturn - * syscall - */ - if (PLAT_TRAMPOLINE_STUFF_LINE) - __clear_user(frame->rs_code, PLAT_TRAMPOLINE_STUFF_LINE); - err |= __put_user(0x24020000 + __NR_rt_sigreturn, frame->rs_code + 0); - err |= __put_user(0x0000000c , frame->rs_code + 1); - flush_cache_sigtramp((unsigned long) frame->rs_code); + install_sigtramp(frame->rs_code, __NR_rt_sigreturn); /* Create siginfo. */ err |= copy_siginfo_to_user(&frame->rs_info, info); diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 8639e24732a..806ed073e54 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -7,6 +7,7 @@ * Copyright (C) 1994 - 2000 Ralf Baechle * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ +#include #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) @@ -392,16 +394,30 @@ static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 *sc) struct sigframe { u32 sf_ass[4]; /* argument save space for o32 */ +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 sf_pad[2]; +#else u32 sf_code[2]; /* signal trampoline */ +#endif struct sigcontext32 sf_sc; sigset_t sf_mask; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ +#endif }; struct rt_sigframe32 { u32 rs_ass[4]; /* argument save space for o32 */ +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 rs_pad[2]; +#else u32 rs_code[2]; /* signal trampoline */ +#endif compat_siginfo_t rs_info; struct ucontext32 rs_uc; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */ +#endif }; int copy_siginfo_to_user32(compat_siginfo_t *to, siginfo_t *from) diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 3544208d4b4..f47c3aaaec8 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -15,6 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include +#include #include #include #include @@ -36,6 +38,7 @@ #include #include #include +#include #include "signal-common.h" @@ -62,17 +65,18 @@ struct ucontextn32 { sigset_t uc_sigmask; /* mask last for extensibility */ }; -#if PLAT_TRAMPOLINE_STUFF_LINE -#define __tramp __attribute__((aligned(PLAT_TRAMPOLINE_STUFF_LINE))) -#else -#define __tramp -#endif - struct rt_sigframe_n32 { u32 rs_ass[4]; /* argument save space for o32 */ - u32 rs_code[2] __tramp; /* signal trampoline */ - struct siginfo rs_info __tramp; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 rs_pad[2]; +#else + u32 rs_code[2]; /* signal trampoline */ +#endif + struct siginfo rs_info; struct ucontextn32 rs_uc; +#if ICACHE_REFILLS_WORKAROUND_WAR + u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ +#endif }; save_static_function(sysn32_rt_sigreturn); @@ -137,17 +141,7 @@ void setup_rt_frame_n32(struct k_sigaction * ka, if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - /* - * Set up the return code ... - * - * li v0, __NR_rt_sigreturn - * syscall - */ - if (PLAT_TRAMPOLINE_STUFF_LINE) - __clear_user(frame->rs_code, PLAT_TRAMPOLINE_STUFF_LINE); - err |= __put_user(0x24020000 + __NR_N32_rt_sigreturn, frame->rs_code + 0); - err |= __put_user(0x0000000c , frame->rs_code + 1); - flush_cache_sigtramp((unsigned long) frame->rs_code); + install_sigtramp(frame->rs_code, __NR_N32_rt_sigreturn); /* Create siginfo. */ err |= copy_siginfo_to_user(&frame->rs_info, info); -- cgit v1.2.3 From 260c96738cf30f489108cd0fb3f10dcd11cbb5ca Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 16 Jun 2005 20:39:12 +0000 Subject: Mark __die() "noreturn" for real. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 9419a3542c2..b502dc970b3 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -254,8 +254,9 @@ void show_registers(struct pt_regs *regs) static DEFINE_SPINLOCK(die_lock); -NORET_TYPE void __die(const char * str, struct pt_regs * regs, - const char * file, const char * func, unsigned long line) +NORET_TYPE void ATTRIB_NORET __die(const char * str, struct pt_regs * regs, + const char * file, const char * func, + unsigned long line) { static int die_counter; -- cgit v1.2.3 From 3b2396d972ce030e942fef9fcbea1e411b1a62db Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Wed, 22 Jun 2005 20:43:29 +0000 Subject: Use correct names for bits in the R3k cp0.status register. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 67 +++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 26 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b502dc970b3..46636a2fe98 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -9,7 +9,7 @@ * Copyright (C) 1999 Silicon Graphics, Inc. * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000, 01 MIPS Technologies, Inc. - * Copyright (C) 2002, 2003, 2004 Maciej W. Rozycki + * Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki */ #include #include @@ -203,32 +203,47 @@ void show_regs(struct pt_regs *regs) printk("Status: %08x ", (uint32_t) regs->cp0_status); - if (regs->cp0_status & ST0_KX) - printk("KX "); - if (regs->cp0_status & ST0_SX) - printk("SX "); - if (regs->cp0_status & ST0_UX) - printk("UX "); - switch (regs->cp0_status & ST0_KSU) { - case KSU_USER: - printk("USER "); - break; - case KSU_SUPERVISOR: - printk("SUPERVISOR "); - break; - case KSU_KERNEL: - printk("KERNEL "); - break; - default: - printk("BAD_MODE "); - break; + if (current_cpu_data.isa_level == MIPS_CPU_ISA_I) { + if (regs->cp0_status & ST0_KUO) + printk("KUo "); + if (regs->cp0_status & ST0_IEO) + printk("IEo "); + if (regs->cp0_status & ST0_KUP) + printk("KUp "); + if (regs->cp0_status & ST0_IEP) + printk("IEp "); + if (regs->cp0_status & ST0_KUC) + printk("KUc "); + if (regs->cp0_status & ST0_IEC) + printk("IEc "); + } else { + if (regs->cp0_status & ST0_KX) + printk("KX "); + if (regs->cp0_status & ST0_SX) + printk("SX "); + if (regs->cp0_status & ST0_UX) + printk("UX "); + switch (regs->cp0_status & ST0_KSU) { + case KSU_USER: + printk("USER "); + break; + case KSU_SUPERVISOR: + printk("SUPERVISOR "); + break; + case KSU_KERNEL: + printk("KERNEL "); + break; + default: + printk("BAD_MODE "); + break; + } + if (regs->cp0_status & ST0_ERL) + printk("ERL "); + if (regs->cp0_status & ST0_EXL) + printk("EXL "); + if (regs->cp0_status & ST0_IE) + printk("IE "); } - if (regs->cp0_status & ST0_ERL) - printk("ERL "); - if (regs->cp0_status & ST0_EXL) - printk("EXL "); - if (regs->cp0_status & ST0_IE) - printk("IE "); printk("\n"); printk("Cause : %08x\n", cause); -- cgit v1.2.3 From c4559f67b73d6c34fde0faac5c6c890a2cf3527c Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Thu, 23 Jun 2005 15:57:15 +0000 Subject: Always use ".set mips3" rather than select between "mips2" or "mips3" for assembling ll/sc sequences to avoid problems with 64-bit configurations. Signed-off-by: Ralf Baechle --- arch/mips/kernel/semaphore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/semaphore.c b/arch/mips/kernel/semaphore.c index dbb145ee00a..1265358cdca 100644 --- a/arch/mips/kernel/semaphore.c +++ b/arch/mips/kernel/semaphore.c @@ -42,7 +42,7 @@ static inline int __sem_update_count(struct semaphore *sem, int incr) if (cpu_has_llsc && R10000_LLSC_WAR) { __asm__ __volatile__( - " .set mips2 \n" + " .set mips3 \n" "1: ll %0, %2 # __sem_update_count \n" " sra %1, %0, 31 \n" " not %1 \n" @@ -55,7 +55,7 @@ static inline int __sem_update_count(struct semaphore *sem, int incr) : "r" (incr), "m" (sem->count)); } else if (cpu_has_llsc) { __asm__ __volatile__( - " .set mips2 \n" + " .set mips3 \n" "1: ll %0, %2 # __sem_update_count \n" " sra %1, %0, 31 \n" " not %1 \n" -- cgit v1.2.3 From c134a5ecdb8f4aee09feca0d4d395915e752fcb8 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 30 Jun 2005 09:42:00 +0000 Subject: Avoid defining variables in the middle of a block which breaks older compilers. Signed-off-by: Ralf Baechle --- arch/mips/kernel/ptrace.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 2441e32ce82..74283369a1e 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -177,19 +177,22 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) write_c0_status(flags); break; } - case DSP_BASE ... DSP_BASE + 5: + case DSP_BASE ... DSP_BASE + 5: { + dspreg_t *dregs; + if (!cpu_has_dsp) { tmp = 0; ret = -EIO; goto out_tsk; } if (child->thread.dsp.used_dsp) { - dspreg_t *dregs = __get_dsp_regs(child); + dregs = __get_dsp_regs(child); tmp = (unsigned long) (dregs[addr - DSP_BASE]); } else { tmp = -1; /* DSP registers yet used */ } break; + } case DSP_CONTROL: if (!cpu_has_dsp) { tmp = 0; @@ -270,15 +273,18 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) else child->thread.fpu.soft.fcr31 = data; break; - case DSP_BASE ... DSP_BASE + 5: + case DSP_BASE ... DSP_BASE + 5: { + dspreg_t *dregs; + if (!cpu_has_dsp) { ret = -EIO; break; } - dspreg_t *dregs = __get_dsp_regs(child); + dregs = __get_dsp_regs(child); dregs[addr - DSP_BASE] = data; break; + } case DSP_CONTROL: if (!cpu_has_dsp) { ret = -EIO; -- cgit v1.2.3 From 6e760c8dae7d6c47eff011dd4aad53c94d30494b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 6 Jul 2005 12:08:11 +0000 Subject: Rename CONFIG_CPU_MIPS{32,64} to CONFIG_CPU_MIPS{32|64}_R1. Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 4 ++-- arch/mips/kernel/r4k_switch.S | 2 +- arch/mips/kernel/traps.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index d54964d52c8..0867417032f 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -28,8 +28,8 @@ obj-$(CONFIG_CPU_RM9000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_NEVADA) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R10000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_SB1) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS32_R1) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS64_R1) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index d2afbd19a9c..27361f44def 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -165,7 +165,7 @@ LEAF(_init_fpu) 1: #endif -#ifdef CONFIG_CPU_MIPS32 +#ifdef CONFIG_CPU_MIPS32_R1 mtc1 t1, $f0 mtc1 t1, $f1 mtc1 t1, $f2 diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 46636a2fe98..b2fa607eeeb 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -864,7 +864,7 @@ asmlinkage void cache_parity_error(void) reg_val & (1<<22) ? "E0 " : ""); printk("IDX: 0x%08x\n", reg_val & ((1<<22)-1)); -#if defined(CONFIG_CPU_MIPS32) || defined (CONFIG_CPU_MIPS64) +#if defined(CONFIG_CPU_MIPS32_R1) || defined(CONFIG_CPU_MIPS64_R1) if (reg_val & (1<<22)) printk("DErrAddr0: 0x%0*lx\n", field, read_c0_derraddr0()); -- cgit v1.2.3 From b490ff42709546d5cf6b631c1a84a5f4fcb020e4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 11 Jul 2005 11:53:44 +0000 Subject: Temporary hack for Qemu and MIPSsim until they get a proper ELF loader. Signed-off-by: Ralf Baechle --- arch/mips/kernel/head.S | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 9f692716935..d7d7de7cdb4 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -131,6 +131,14 @@ EXPORT(stext) # used for profiling EXPORT(_stext) +#ifdef CONFIG_QEMU + /* + * Give us a fighting chance of running if execution beings at the + * kernel load address. This is needed because this platform does + * not have a ELF loader yet. + */ + j kernel_entry +#endif __INIT NESTED(kernel_entry, 16, sp) # kernel entry point @@ -166,6 +174,10 @@ NESTED(kernel_entry, 16, sp) # kernel entry point j start_kernel END(kernel_entry) +#ifdef CONFIG_QEMU + __INIT +#endif + #ifdef CONFIG_SMP /* * SMP slave cpus entry point. Board specific code for bootstrap calls this -- cgit v1.2.3 From 129bc8f78b468df6824dd1584829f10aa3a69c27 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 11 Jul 2005 20:45:51 +0000 Subject: Setup_frame is now returning a success value. Signed-off-by: Ralf Baechle --- arch/mips/kernel/process.c | 10 +++++----- arch/mips/kernel/signal.c | 26 +++++++++++++++----------- arch/mips/kernel/signal32.c | 16 +++++++++------- arch/mips/kernel/signal_n32.c | 5 +++-- 4 files changed, 32 insertions(+), 25 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 98432097a86..4fe3d5715c4 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -62,9 +62,9 @@ extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); /* * Native o32 and N64 ABI without DSP ASE */ -extern void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, +extern int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set); -extern void setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, +extern int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info); struct mips_abi mips_abi = { @@ -79,9 +79,9 @@ struct mips_abi mips_abi = { /* * o32 compatibility on 64-bit kernels, without DSP ASE */ -extern void setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, +extern int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set); -extern void setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, +extern int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info); struct mips_abi mips_abi_32 = { @@ -95,7 +95,7 @@ struct mips_abi mips_abi_32 = { /* * N32 on 64-bit kernels, without DSP ASE */ -extern void setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs, +extern int setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info); struct mips_abi mips_abi_n32 = { diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 8679ccff870..9202a17db8f 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -278,7 +278,7 @@ badframe: } #ifdef CONFIG_TRAD_SIGNALS -void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, +int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set) { struct sigframe *frame; @@ -317,14 +317,15 @@ void setup_frame(struct k_sigaction * ka, struct pt_regs *regs, current->comm, current->pid, frame, regs->cp0_epc, frame->regs[31]); #endif - return; + return 1; give_sigsegv: force_sigsegv(signr, current); + return 0; } #endif -void setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, +int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info) { struct rt_sigframe *frame; @@ -376,18 +377,21 @@ void setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); #endif - return; + return 1; give_sigsegv: force_sigsegv(signr, current); + return 0; } extern void setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info); -static inline void handle_signal(unsigned long sig, siginfo_t *info, +static inline int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { + int ret; + switch(regs->regs[0]) { case ERESTART_RESTARTBLOCK: case ERESTARTNOHAND: @@ -407,9 +411,9 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, regs->regs[0] = 0; /* Don't deal with this again. */ if (sig_uses_siginfo(ka)) - current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); + ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); else - current->thread.abi->setup_frame(ka, regs, sig, oldset); + ret = current->thread.abi->setup_frame(ka, regs, sig, oldset); spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -417,6 +421,8 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + + return ret; } int do_signal(sigset_t *oldset, struct pt_regs *regs) @@ -440,10 +446,8 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); - if (signr > 0) { - handle_signal(signr, &info, &ka, oldset, regs); - return 1; - } + if (signr > 0) + return handle_signal(signr, &info, &ka, oldset, regs); no_signal: /* diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 806ed073e54..dbe82130312 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -769,9 +769,11 @@ give_sigsegv: force_sigsegv(signr, current); } -static inline void handle_signal(unsigned long sig, siginfo_t *info, +static inline int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) { + int ret; + switch (regs->regs[0]) { case ERESTART_RESTARTBLOCK: case ERESTARTNOHAND: @@ -791,9 +793,9 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, regs->regs[0] = 0; /* Don't deal with this again. */ if (ka->sa.sa_flags & SA_SIGINFO) - current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); + ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info); else - current->thread.abi->setup_frame(ka, regs, sig, oldset); + ret = current->thread.abi->setup_frame(ka, regs, sig, oldset); spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -801,6 +803,8 @@ static inline void handle_signal(unsigned long sig, siginfo_t *info, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + + return ret; } int do_signal32(sigset_t *oldset, struct pt_regs *regs) @@ -824,10 +828,8 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); - if (signr > 0) { - handle_signal(signr, &info, &ka, oldset, regs); - return 1; - } + if (signr > 0) + return handle_signal(signr, &info, &ka, oldset, regs); no_signal: /* diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index f47c3aaaec8..ec61b2670ba 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -130,7 +130,7 @@ badframe: force_sig(SIGSEGV, current); } -void setup_rt_frame_n32(struct k_sigaction * ka, +int setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info) { struct rt_sigframe_n32 *frame; @@ -184,8 +184,9 @@ void setup_rt_frame_n32(struct k_sigaction * ka, current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); #endif - return; + return 1; give_sigsegv: force_sigsegv(signr, current); + return 0; } -- cgit v1.2.3 From bbc7f22f6dca8a075b565ade49e9a982f89707c3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 12 Jul 2005 16:12:05 +0000 Subject: Detect the 34K. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 5 +++++ arch/mips/kernel/proc.c | 1 + 2 files changed, 6 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 2b6db681417..e40bd6fccea 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -104,6 +104,7 @@ static inline void check_wait(void) /* case CPU_20KC:*/ case CPU_24K: case CPU_25KF: + case CPU_34K: cpu_wait = r4k_wait; printk(" available.\n"); break; @@ -538,6 +539,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c) /* Probe for L2 cache */ c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; break; + case PRID_IMP_34K: + c->cputype = CPU_34K; + c->isa_level = MIPS_CPU_ISA_M32; + break; } } diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index cf31d3952d6..1bd40af508e 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -72,6 +72,7 @@ static const char *cpu_name[] = { [CPU_20KC] = "MIPS 20Kc", [CPU_24K] = "MIPS 24K", [CPU_25KF] = "MIPS 25Kf", + [CPU_34K] = "MIPS 34K", [CPU_VR4111] = "NEC VR4111", [CPU_VR4121] = "NEC VR4121", [CPU_VR4122] = "NEC VR4122", -- cgit v1.2.3 From ec74e361f1e71a2498e48b62abdc4bd8d2423354 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Jul 2005 11:48:45 +0000 Subject: Mark a few variables __read_mostly. Signed-off-by: Ralf Baechle --- arch/mips/kernel/setup.c | 9 +++++---- arch/mips/kernel/time.c | 9 ++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 9253dccefd0..d86affa2127 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -37,12 +37,13 @@ #include #include +#include #include #include #include #include -struct cpuinfo_mips cpu_data[NR_CPUS]; +struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly; EXPORT_SYMBOL(cpu_data); @@ -62,8 +63,8 @@ EXPORT_SYMBOL(PCI_DMA_BUS_IS_PHYS); * * These are initialized so they are in the .data section */ -unsigned long mips_machtype = MACH_UNKNOWN; -unsigned long mips_machgroup = MACH_GROUP_UNKNOWN; +unsigned long mips_machtype __read_mostly = MACH_UNKNOWN; +unsigned long mips_machgroup __read_mostly = MACH_GROUP_UNKNOWN; EXPORT_SYMBOL(mips_machtype); EXPORT_SYMBOL(mips_machgroup); @@ -77,7 +78,7 @@ static char command_line[CL_SIZE]; * mips_io_port_base is the begin of the address space to which x86 style * I/O ports are mapped. */ -const unsigned long mips_io_port_base = -1; +const unsigned long mips_io_port_base __read_mostly = -1; EXPORT_SYMBOL(mips_io_port_base); /* diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 0dd0df7a3b0..fbc153c8f83 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -76,7 +77,7 @@ int (*rtc_set_mmss)(unsigned long); static unsigned int sll32_usecs_per_cycle; /* how many counter cycles in a jiffy */ -static unsigned long cycles_per_jiffy; +static unsigned long cycles_per_jiffy __read_mostly; /* Cycle counter value at the previous timer interrupt.. */ static unsigned int timerhi, timerlo; @@ -98,7 +99,10 @@ static unsigned int null_hpt_read(void) return 0; } -static void null_hpt_init(unsigned int count) { /* nothing */ } +static void null_hpt_init(unsigned int count) +{ + /* nothing */ +} /* @@ -224,7 +228,6 @@ int do_settimeofday(struct timespec *tv) set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); ntp_clear(); - write_sequnlock_irq(&xtime_lock); clock_was_set(); return 0; -- cgit v1.2.3 From 7db36c858c01218bf02931c39076b082c42d964c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Jul 2005 11:48:45 +0000 Subject: Add inotify syscalls for MIPS. Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall32-o32.S | 4 +++- arch/mips/kernel/scall64-64.S | 3 +++ arch/mips/kernel/scall64-n32.S | 3 +++ arch/mips/kernel/scall64-o32.S | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index c389dbaa279..fd1823c1657 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -624,7 +624,9 @@ einval: li v0, -EINVAL sys sys_request_key 4 sys sys_keyctl 5 sys sys_set_thread_area 1 - + sys sys_inotify_init 0 + sys sys_inotify_add_watch 3 /* 4285 */ + sys sys_inotify_rm_watch 2 .endm /* We pre-compute the number of _instruction_ bytes needed to diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index d11f99b0ae5..9085838d6ce 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -450,3 +450,6 @@ sys_call_table: PTR sys_request_key /* 5240 */ PTR sys_keyctl PTR sys_set_thread_area + PTR sys_inotify_init + PTR sys_inotify_add_watch + PTR sys_inotify_rm_watch /* 5245 */ diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index cb671ef5e19..0dfb34bf979 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -364,3 +364,6 @@ EXPORT(sysn32_call_table) PTR sys_request_key PTR sys_keyctl /* 6245 */ PTR sys_set_thread_area + sys sys_inotify_init + sys sys_inotify_add_watch + sys sys_inotify_rm_watch diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index deb7f932e28..5a16401e443 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -486,4 +486,7 @@ sys_call_table: PTR sys_request_key PTR sys_keyctl PTR sys_set_thread_area + PTR sys_inotify_init + PTR sys_inotify_add_watch /* 4285 */ + PTR sys_inotify_rm_watch .size sys_call_table,.-sys_call_table -- cgit v1.2.3 From 569f75bd02d20043c4baf9fc38d937f37e7572b0 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Jul 2005 18:20:33 +0000 Subject: Use an irq_enable_hazard hazard barrier in unmask_mips_irq. This hasn't been an actual bug, so it's more a change to be 100% compliant with the requirements of the architecture spec. Similar fix to mask_mips_irq where there was a slightly less theoretical chance of getting hit. Signed-off-by: Ralf Baechle --- arch/mips/kernel/irq_cpu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 905ff843a68..060722e42c5 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -40,11 +40,13 @@ static int mips_cpu_irq_base; static inline void unmask_mips_irq(unsigned int irq) { set_c0_status(0x100 << (irq - mips_cpu_irq_base)); + irq_enable_hazard(); } static inline void mask_mips_irq(unsigned int irq) { clear_c0_status(0x100 << (irq - mips_cpu_irq_base)); + irq_disable_hazard(); } static inline void mips_cpu_irq_enable(unsigned int irq) -- cgit v1.2.3 From 55d04dff0fcf5d1c3f0d6edf6df86d82fa4c053b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 13 Jul 2005 19:22:45 +0000 Subject: New kernel option nowait allows disabling the use of the wait instruction. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index e40bd6fccea..53e4496de6b 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -71,11 +71,27 @@ static void au1k_wait(void) : : "r" (au1k_wait)); } +static int __initdata nowait = 0; + +int __init wait_disable(char *s) +{ + nowait = 1; + + return 1; +} + +__setup("nowait", wait_disable); + static inline void check_wait(void) { struct cpuinfo_mips *c = ¤t_cpu_data; printk("Checking for 'wait' instruction... "); + if (nowait) { + printk (" disabled.\n"); + return; + } + switch (c->cputype) { case CPU_R3081: case CPU_R3081E: -- cgit v1.2.3 From 8f40611d2b184ca5d525075d273854929cf8d1d0 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 14 Jul 2005 07:34:18 +0000 Subject: Detect the MIPS R2 vectored interrupt, external interrupt controller options and the precense of the MT ASE. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 53e4496de6b..844126b39ed 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -501,6 +501,12 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) c->ases |= MIPS_ASE_SMARTMIPS; if (config3 & MIPS_CONF3_DSP) c->ases |= MIPS_ASE_DSP; + if (config3 & MIPS_CONF3_VINT) + c->options |= MIPS_CPU_VINT; + if (config3 & MIPS_CONF3_VEIC) + c->options |= MIPS_CPU_VEIC; + if (config3 & MIPS_CONF3_MT) + c->ases |= MIPS_ASE_MIPSMT; return config3 & MIPS_CONF_M; } -- cgit v1.2.3 From a0c3a5b5a84df11cf6a44fc04cb6f7c0525123a8 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 14 Jul 2005 07:39:46 +0000 Subject: Prevent gcc from optimizing a few functions away completly. Signed-off-by: Ralf Baechle --- arch/mips/kernel/gdb-stub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index 7c46b336c7d..ba0afb4a649 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -1039,12 +1039,12 @@ void adel(void) * malloc is needed by gdb client in "call func()", even a private one * will make gdb happy */ -static void *malloc(size_t size) +static void * __attribute_used__ malloc(size_t size) { return kmalloc(size, GFP_ATOMIC); } -static void free(void *where) +static void __attribute_used__ free (void *where) { kfree(where); } -- cgit v1.2.3 From 7e35952baa9d7424dfb95ca8aff7239a1f6ec011 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 14 Jul 2005 09:42:32 +0000 Subject: Move Origin crapola into a machine-specific header file. Signed-off-by: Ralf Baechle --- arch/mips/kernel/head.S | 43 ++++++------------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index d7d7de7cdb4..d2de5d025db 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -22,11 +22,8 @@ #include #include #include -#ifdef CONFIG_SGI_IP27 -#include -#include -#include -#endif + +#include .macro ARC64_TWIDDLE_PC #if defined(CONFIG_ARC64) || defined(CONFIG_MAPPED_KERNEL) @@ -38,18 +35,6 @@ #endif .endm -#ifdef CONFIG_SGI_IP27 - /* - * outputs the local nasid into res. IP27 stuff. - */ - .macro GET_NASID_ASM res - dli \res, LOCAL_HUB_ADDR(NI_STATUS_REV_ID) - ld \res, (\res) - and \res, NSRI_NODEID_MASK - dsrl \res, NSRI_NODEID_SHFT - .endm -#endif /* CONFIG_SGI_IP27 */ - /* * inputs are the text nasid in t1, data nasid in t2. */ @@ -142,13 +127,10 @@ EXPORT(_stext) __INIT NESTED(kernel_entry, 16, sp) # kernel entry point - setup_c0_status_pri -#ifdef CONFIG_SGI_IP27 - GET_NASID_ASM t1 - move t2, t1 # text and data are here - MAPPED_KERNEL_SETUP_TLB -#endif /* IP27 */ + kernel_entry_setup # cpu specific setup + + setup_c0_status_pri ARC64_TWIDDLE_PC @@ -185,20 +167,7 @@ NESTED(kernel_entry, 16, sp) # kernel entry point */ NESTED(smp_bootstrap, 16, sp) setup_c0_status_sec - -#ifdef CONFIG_SGI_IP27 - GET_NASID_ASM t1 - dli t0, KLDIR_OFFSET + (KLI_KERN_VARS * KLDIR_ENT_SIZE) + \ - KLDIR_OFF_POINTER + CAC_BASE - dsll t1, NASID_SHFT - or t0, t0, t1 - ld t0, 0(t0) # t0 points to kern_vars struct - lh t1, KV_RO_NASID_OFFSET(t0) - lh t2, KV_RW_NASID_OFFSET(t0) - MAPPED_KERNEL_SETUP_TLB - ARC64_TWIDDLE_PC -#endif /* CONFIG_SGI_IP27 */ - + smp_slave_setup j start_secondary END(smp_bootstrap) #endif /* CONFIG_SMP */ -- cgit v1.2.3 From e01402b115cccb6357f956649487aca2c6f7fbba Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 14 Jul 2005 15:57:16 +0000 Subject: More AP / SP bits for the 34K, the Malta bits and things. Still wants a little polishing. Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 4 + arch/mips/kernel/genex.S | 32 ++ arch/mips/kernel/irq-msc01.c | 8 +- arch/mips/kernel/rtlx.c | 341 +++++++++++ arch/mips/kernel/traps.c | 227 +++++++- arch/mips/kernel/vpe.c | 1295 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1890 insertions(+), 17 deletions(-) create mode 100644 arch/mips/kernel/rtlx.c create mode 100644 arch/mips/kernel/vpe.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 0867417032f..0f527063a8a 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -34,12 +34,16 @@ obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o +obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o + obj-$(CONFIG_NO_ISA) += dma-no-isa.o obj-$(CONFIG_I8259) += i8259.o obj-$(CONFIG_IRQ_CPU) += irq_cpu.o obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o obj-$(CONFIG_IRQ_CPU_RM9K) += irq-rm9000.o obj-$(CONFIG_IRQ_MV64340) += irq-mv6434x.o +obj-$(CONFIG_MIPS_BOARDS_GEN) += irq-msc01.o obj-$(CONFIG_32BIT) += scall32-o32.o obj-$(CONFIG_64BIT) += scall64-64.o diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 349ec301168..fd904d1e419 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -147,6 +147,38 @@ NESTED(except_vec_ejtag_debug, 0, sp) __FINIT +/* + * Vectored interrupt handler. + * This prototype is copied to ebase + n*IntCtl.VS and patched + * to invoke the handler + */ +NESTED(except_vec_vi, 0, sp) + SAVE_SOME + SAVE_AT + .set push + .set noreorder +EXPORT(except_vec_vi_lui) + lui v0, 0 /* Patched */ + j except_vec_vi_handler +EXPORT(except_vec_vi_ori) + ori v0, 0 /* Patched */ + .set pop + END(except_vec_vi) +EXPORT(except_vec_vi_end) + +/* + * Common Vectored Interrupt code + * Complete the register saves and invoke the handler which is passed in $v0 + */ +NESTED(except_vec_vi_handler, 0, sp) + SAVE_TEMP + SAVE_STATIC + CLI + move a0, sp + jalr v0 + j ret_from_irq + END(except_vec_vi_handler) + /* * EJTAG debug exception handler. */ diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index bf759e33c5e..3f653c7cfbf 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c @@ -74,7 +74,7 @@ static void disable_msc_irq(unsigned int irq) static void level_mask_and_ack_msc_irq(unsigned int irq) { mask_msc_irq(irq); - if (!cpu_has_ei) + if (!cpu_has_veic) MSCIC_WRITE(MSC01_IC_EOI, 0); } @@ -84,7 +84,7 @@ static void level_mask_and_ack_msc_irq(unsigned int irq) static void edge_mask_and_ack_msc_irq(unsigned int irq) { mask_msc_irq(irq); - if (!cpu_has_ei) + if (!cpu_has_veic) MSCIC_WRITE(MSC01_IC_EOI, 0); else { u32 r; @@ -166,14 +166,14 @@ void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq) switch (imp->im_type) { case MSC01_IRQ_EDGE: irq_desc[base+n].handler = &msc_edgeirq_type; - if (cpu_has_ei) + if (cpu_has_veic) MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); else MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); break; case MSC01_IRQ_LEVEL: irq_desc[base+n].handler = &msc_levelirq_type; - if (cpu_has_ei) + if (cpu_has_veic) MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); else MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl); diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c new file mode 100644 index 00000000000..8c81f3cb4e2 --- /dev/null +++ b/arch/mips/kernel/rtlx.c @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTLX_MAJOR 64 +#define RTLX_TARG_VPE 1 + +struct rtlx_info *rtlx; +static int major; +static char module_name[] = "rtlx"; +static inline int spacefree(int read, int write, int size); + +static struct chan_waitqueues { + wait_queue_head_t rt_queue; + wait_queue_head_t lx_queue; +} channel_wqs[RTLX_CHANNELS]; + +static struct irqaction irq; +static int irq_num; + +extern void *vpe_get_shared(int index); + +static void rtlx_dispatch(struct pt_regs *regs) +{ + do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs); +} + +irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + irqreturn_t r = IRQ_HANDLED; + int i; + + for (i = 0; i < RTLX_CHANNELS; i++) { + struct rtlx_channel *chan = &rtlx->channel[i]; + + if (chan->lx_read != chan->lx_write) + wake_up_interruptible(&channel_wqs[i].lx_queue); + } + + return r; +} + +void dump_rtlx(void) +{ + int i; + + printk("id 0x%lx state %d\n", rtlx->id, rtlx->state); + + for (i = 0; i < RTLX_CHANNELS; i++) { + struct rtlx_channel *chan = &rtlx->channel[i]; + + printk(" rt_state %d lx_state %d buffer_size %d\n", + chan->rt_state, chan->lx_state, chan->buffer_size); + + printk(" rt_read %d rt_write %d\n", + chan->rt_read, chan->rt_write); + + printk(" lx_read %d lx_write %d\n", + chan->lx_read, chan->lx_write); + + printk(" rt_buffer <%s>\n", chan->rt_buffer); + printk(" lx_buffer <%s>\n", chan->lx_buffer); + } +} + +/* call when we have the address of the shared structure from the SP side. */ +static int rtlx_init(struct rtlx_info *rtlxi) +{ + int i; + + if (rtlxi->id != RTLX_ID) { + printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi); + return (-ENOEXEC); + } + + /* initialise the wait queues */ + for (i = 0; i < RTLX_CHANNELS; i++) { + init_waitqueue_head(&channel_wqs[i].rt_queue); + init_waitqueue_head(&channel_wqs[i].lx_queue); + } + + /* set up for interrupt handling */ + memset(&irq, 0, sizeof(struct irqaction)); + + if (cpu_has_vint) { + set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); + } + + irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ; + irq.handler = rtlx_interrupt; + irq.flags = SA_INTERRUPT; + irq.name = "RTLX"; + irq.dev_id = rtlx; + setup_irq(irq_num, &irq); + + rtlx = rtlxi; + return (0); +} + +/* only allow one open process at a time to open each channel */ +static int rtlx_open(struct inode *inode, struct file *filp) +{ + int minor, ret; + struct rtlx_channel *chan; + + /* assume only 1 device at the mo. */ + minor = MINOR(inode->i_rdev); + + if (rtlx == NULL) { + struct rtlx_info **p; + if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { + printk(" vpe_get_shared is NULL. Has an SP program been loaded?\n"); + return (-EFAULT); + } + + if (*p == NULL) { + printk(" vpe_shared %p %p\n", p, *p); + return (-EFAULT); + } + + if ((ret = rtlx_init(*p)) < 0) + return (ret); + } + + chan = &rtlx->channel[minor]; + + /* already open? */ + if (chan->lx_state == RTLX_STATE_OPENED) + return (-EBUSY); + + chan->lx_state = RTLX_STATE_OPENED; + return (0); +} + +static int rtlx_release(struct inode *inode, struct file *filp) +{ + int minor; + + minor = MINOR(inode->i_rdev); + rtlx->channel[minor].lx_state = RTLX_STATE_UNUSED; + return (0); +} + +static unsigned int rtlx_poll(struct file *file, poll_table * wait) +{ + int minor; + unsigned int mask = 0; + struct rtlx_channel *chan; + + minor = MINOR(file->f_dentry->d_inode->i_rdev); + chan = &rtlx->channel[minor]; + + poll_wait(file, &channel_wqs[minor].rt_queue, wait); + poll_wait(file, &channel_wqs[minor].lx_queue, wait); + + /* data available to read? */ + if (chan->lx_read != chan->lx_write) + mask |= POLLIN | POLLRDNORM; + + /* space to write */ + if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size)) + mask |= POLLOUT | POLLWRNORM; + + return (mask); +} + +static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count, + loff_t * ppos) +{ + size_t fl = 0L; + int minor; + struct rtlx_channel *lx; + DECLARE_WAITQUEUE(wait, current); + + minor = MINOR(file->f_dentry->d_inode->i_rdev); + lx = &rtlx->channel[minor]; + + /* data available? */ + if (lx->lx_write == lx->lx_read) { + if (file->f_flags & O_NONBLOCK) + return (0); // -EAGAIN makes cat whinge + + /* go to sleep */ + add_wait_queue(&channel_wqs[minor].lx_queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (lx->lx_write == lx->lx_read) + schedule(); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&channel_wqs[minor].lx_queue, &wait); + + /* back running */ + } + + /* find out how much in total */ + count = min( count, + (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size); + + /* then how much from the read pointer onwards */ + fl = min( count, (size_t)lx->buffer_size - lx->lx_read); + + copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl); + + /* and if there is anything left at the beginning of the buffer */ + if ( count - fl ) + copy_to_user (buffer + fl, lx->lx_buffer, count - fl); + + /* update the index */ + lx->lx_read += count; + lx->lx_read %= lx->buffer_size; + + return (count); +} + +static inline int spacefree(int read, int write, int size) +{ + if (read == write) { + /* never fill the buffer completely, so indexes are always equal if empty + and only empty, or !equal if data available */ + return (size - 1); + } + + return ((read + size - write) % size) - 1; +} + +static ssize_t rtlx_write(struct file *file, const char __user * buffer, + size_t count, loff_t * ppos) +{ + int minor; + struct rtlx_channel *rt; + size_t fl; + DECLARE_WAITQUEUE(wait, current); + + minor = MINOR(file->f_dentry->d_inode->i_rdev); + rt = &rtlx->channel[minor]; + + /* any space left... */ + if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) { + + if (file->f_flags & O_NONBLOCK) + return (-EAGAIN); + + add_wait_queue(&channel_wqs[minor].rt_queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) + schedule(); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&channel_wqs[minor].rt_queue, &wait); + } + + /* total number of bytes to copy */ + count = min( count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) ); + + /* first bit from write pointer to the end of the buffer, or count */ + fl = min(count, (size_t) rt->buffer_size - rt->rt_write); + + copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl); + + /* if there's any left copy to the beginning of the buffer */ + if( count - fl ) + copy_from_user(rt->rt_buffer, buffer + fl, count - fl); + + rt->rt_write += count; + rt->rt_write %= rt->buffer_size; + + return(count); +} + +static struct file_operations rtlx_fops = { + .owner = THIS_MODULE, + .open = rtlx_open, + .release = rtlx_release, + .write = rtlx_write, + .read = rtlx_read, + .poll = rtlx_poll +}; + +static int rtlx_module_init(void) +{ + if ((major = register_chrdev(RTLX_MAJOR, module_name, &rtlx_fops)) < 0) { + printk("rtlx_module_init: unable to register device\n"); + return (-EBUSY); + } + + if (major == 0) + major = RTLX_MAJOR; + + return (0); +} + +static void rtlx_module_exit(void) +{ + unregister_chrdev(major, module_name); +} + +module_init(rtlx_module_init); +module_exit(rtlx_module_exit); +MODULE_DESCRIPTION("MIPS RTLX"); +MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc"); +MODULE_LICENSE("GPL"); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b2fa607eeeb..0a3969aa8dc 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -64,6 +65,9 @@ extern int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp, void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); +void (*board_nmi_handler_setup)(void); +void (*board_ejtag_handler_setup)(void); +void (*board_bind_eic_interrupt)(int irq, int regset); /* * These constant is for searching for possible module text segments. @@ -813,6 +817,12 @@ asmlinkage void do_reserved(struct pt_regs *regs) (regs->cp0_cause & 0x7f) >> 2); } +asmlinkage void do_default_vi(struct pt_regs *regs) +{ + show_regs(regs); + panic("Caught unexpected vectored interrupt."); +} + /* * Some MIPS CPUs can enable/disable for cache parity detection, but do * it different ways. @@ -921,7 +931,11 @@ void nmi_exception_handler(struct pt_regs *regs) while(1) ; } +#define VECTORSPACING 0x100 /* for EI/VI mode */ + +unsigned long ebase; unsigned long exception_handlers[32]; +unsigned long vi_handlers[64]; /* * As a side effect of the way this is implemented we're limited @@ -935,13 +949,156 @@ void *set_except_vector(int n, void *addr) exception_handlers[n] = handler; if (n == 0 && cpu_has_divec) { - *(volatile u32 *)(CAC_BASE + 0x200) = 0x08000000 | + *(volatile u32 *)(ebase + 0x200) = 0x08000000 | (0x03ffffff & (handler >> 2)); - flush_icache_range(CAC_BASE + 0x200, CAC_BASE + 0x204); + flush_icache_range(ebase + 0x200, ebase + 0x204); + } + return (void *)old_handler; +} + +#ifdef CONFIG_CPU_MIPSR2 +/* + * Shadow register allocation + * FIXME: SMP... + */ + +/* MIPSR2 shadow register sets */ +struct shadow_registers { + spinlock_t sr_lock; /* */ + int sr_supported; /* Number of shadow register sets supported */ + int sr_allocated; /* Bitmap of allocated shadow registers */ +} shadow_registers; + +void mips_srs_init(void) +{ +#ifdef CONFIG_CPU_MIPSR2_SRS + shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1; + printk ("%d MIPSR2 register sets available\n", shadow_registers.sr_supported); +#else + shadow_registers.sr_supported = 1; +#endif + shadow_registers.sr_allocated = 1; /* Set 0 used by kernel */ + spin_lock_init(&shadow_registers.sr_lock); +} + +int mips_srs_max(void) +{ + return shadow_registers.sr_supported; +} + +int mips_srs_alloc (void) +{ + struct shadow_registers *sr = &shadow_registers; + unsigned long flags; + int set; + + spin_lock_irqsave(&sr->sr_lock, flags); + + for (set = 0; set < sr->sr_supported; set++) { + if ((sr->sr_allocated & (1 << set)) == 0) { + sr->sr_allocated |= 1 << set; + spin_unlock_irqrestore(&sr->sr_lock, flags); + return set; + } + } + + /* None available */ + spin_unlock_irqrestore(&sr->sr_lock, flags); + return -1; +} + +void mips_srs_free (int set) +{ + struct shadow_registers *sr = &shadow_registers; + unsigned long flags; + + spin_lock_irqsave(&sr->sr_lock, flags); + sr->sr_allocated &= ~(1 << set); + spin_unlock_irqrestore(&sr->sr_lock, flags); +} + +void *set_vi_srs_handler (int n, void *addr, int srs) +{ + unsigned long handler; + unsigned long old_handler = vi_handlers[n]; + u32 *w; + unsigned char *b; + + if (!cpu_has_veic && !cpu_has_vint) + BUG(); + + if (addr == NULL) { + handler = (unsigned long) do_default_vi; + srs = 0; + } + else + handler = (unsigned long) addr; + vi_handlers[n] = (unsigned long) addr; + + b = (unsigned char *)(ebase + 0x200 + n*VECTORSPACING); + + if (srs >= mips_srs_max()) + panic("Shadow register set %d not supported", srs); + + if (cpu_has_veic) { + if (board_bind_eic_interrupt) + board_bind_eic_interrupt (n, srs); + } + else if (cpu_has_vint) { + /* SRSMap is only defined if shadow sets are implemented */ + if (mips_srs_max() > 1) + change_c0_srsmap (0xf << n*4, srs << n*4); + } + + if (srs == 0) { + /* + * If no shadow set is selected then use the default handler + * that does normal register saving and a standard interrupt exit + */ + + extern char except_vec_vi, except_vec_vi_lui; + extern char except_vec_vi_ori, except_vec_vi_end; + const int handler_len = &except_vec_vi_end - &except_vec_vi; + const int lui_offset = &except_vec_vi_lui - &except_vec_vi; + const int ori_offset = &except_vec_vi_ori - &except_vec_vi; + + if (handler_len > VECTORSPACING) { + /* + * Sigh... panicing won't help as the console + * is probably not configured :( + */ + panic ("VECTORSPACING too small"); + } + + memcpy (b, &except_vec_vi, handler_len); + w = (u32 *)(b + lui_offset); + *w = (*w & 0xffff0000) | (((u32)handler >> 16) & 0xffff); + w = (u32 *)(b + ori_offset); + *w = (*w & 0xffff0000) | ((u32)handler & 0xffff); + flush_icache_range((unsigned long)b, (unsigned long)(b+handler_len)); + } + else { + /* + * In other cases jump directly to the interrupt handler + * + * It is the handlers responsibility to save registers if required + * (eg hi/lo) and return from the exception using "eret" + */ + w = (u32 *)b; + *w++ = 0x08000000 | (((u32)handler >> 2) & 0x03fffff); /* j handler */ + *w = 0; + flush_icache_range((unsigned long)b, (unsigned long)(b+8)); } + return (void *)old_handler; } +void *set_vi_handler (int n, void *addr) +{ + return set_vi_srs_handler (n, addr, 0); +} +#endif + /* * This is used by native signal handling */ @@ -1016,10 +1173,18 @@ void __init per_cpu_trap_init(void) if (cpu_has_dsp) set_c0_status(ST0_MX); +#ifdef CONFIG_CPU_MIPSR2 + write_c0_hwrena (0x0000000f); /* Allow rdhwr to all registers */ +#endif + /* - * Some MIPS CPUs have a dedicated interrupt vector which reduces the - * interrupt processing overhead. Use it where available. + * Interrupt handling. */ + if (cpu_has_veic || cpu_has_vint) { + write_c0_ebase (ebase); + /* Setting vector spacing enables EI/VI mode */ + change_c0_intctl (0x3e0, VECTORSPACING); + } if (cpu_has_divec) set_c0_cause(CAUSEF_IV); @@ -1035,13 +1200,41 @@ void __init per_cpu_trap_init(void) tlb_init(); } +/* Install CPU exception handler */ +void __init set_handler (unsigned long offset, void *addr, unsigned long size) +{ + memcpy((void *)(ebase + offset), addr, size); + flush_icache_range(ebase + offset, ebase + offset + size); +} + +/* Install uncached CPU exception handler */ +void __init set_uncached_handler (unsigned long offset, void *addr, unsigned long size) +{ +#ifdef CONFIG_32BIT + unsigned long uncached_ebase = KSEG1ADDR(ebase); +#endif +#ifdef CONFIG_64BIT + unsigned long uncached_ebase = TO_UNCAC(ebase); +#endif + + memcpy((void *)(uncached_ebase + offset), addr, size); +} + void __init trap_init(void) { extern char except_vec3_generic, except_vec3_r4000; - extern char except_vec_ejtag_debug; extern char except_vec4; unsigned long i; + if (cpu_has_veic || cpu_has_vint) + ebase = (unsigned long) alloc_bootmem_low_pages (0x200 + VECTORSPACING*64); + else + ebase = CAC_BASE; + +#ifdef CONFIG_CPU_MIPSR2 + mips_srs_init(); +#endif + per_cpu_trap_init(); /* @@ -1049,7 +1242,7 @@ void __init trap_init(void) * This will be overriden later as suitable for a particular * configuration. */ - memcpy((void *)(CAC_BASE + 0x180), &except_vec3_generic, 0x80); + set_handler(0x180, &except_vec3_generic, 0x80); /* * Setup default vectors @@ -1061,8 +1254,8 @@ void __init trap_init(void) * Copy the EJTAG debug exception vector handler code to it's final * destination. */ - if (cpu_has_ejtag) - memcpy((void *)(CAC_BASE + 0x300), &except_vec_ejtag_debug, 0x80); + if (cpu_has_ejtag && board_ejtag_handler_setup) + board_ejtag_handler_setup (); /* * Only some CPUs have the watch exceptions. @@ -1071,11 +1264,15 @@ void __init trap_init(void) set_except_vector(23, handle_watch); /* - * Some MIPS CPUs have a dedicated interrupt vector which reduces the - * interrupt processing overhead. Use it where available. + * Initialise interrupt handlers */ - if (cpu_has_divec) - memcpy((void *)(CAC_BASE + 0x200), &except_vec4, 0x8); + if (cpu_has_veic || cpu_has_vint) { + int nvec = cpu_has_veic ? 64 : 8; + for (i = 0; i < nvec; i++) + set_vi_handler (i, NULL); + } + else if (cpu_has_divec) + set_handler(0x200, &except_vec4, 0x8); /* * Some CPUs can enable/disable for cache parity detection, but does @@ -1122,6 +1319,10 @@ void __init trap_init(void) //set_except_vector(15, handle_ndc); } + + if (board_nmi_handler_setup) + board_nmi_handler_setup(); + if (cpu_has_fpu && !cpu_has_nofpuex) set_except_vector(15, handle_fpe); @@ -1146,5 +1347,5 @@ void __init trap_init(void) signal32_init(); #endif - flush_icache_range(CAC_BASE, CAC_BASE + 0x400); + flush_icache_range(ebase, ebase + 0x400); } diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c new file mode 100644 index 00000000000..6bf42ba08f0 --- /dev/null +++ b/arch/mips/kernel/vpe.c @@ -0,0 +1,1295 @@ +/* + * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + */ + +/* + * VPE support module + * + * Provides support for loading a MIPS SP program on VPE1. + * The SP enviroment is rather simple, no tlb's. It needs to be relocatable + * (or partially linked). You should initialise your stack in the startup + * code. This loader looks for the symbol __start and sets up + * execution to resume from there. The MIPS SDE kit contains suitable examples. + * + * To load and run, simply cat a SP 'program file' to /dev/vpe1. + * i.e cat spapp >/dev/vpe1. + * + * You'll need to have the following device files. + * mknod /dev/vpe0 c 63 0 + * mknod /dev/vpe1 c 63 1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef void *vpe_handle; + +// defined here because the kernel module loader doesn't have +// anything to do with it. +#define SHN_MIPS_SCOMMON 0xff03 + +#ifndef ARCH_SHF_SMALL +#define ARCH_SHF_SMALL 0 +#endif + +/* If this is set, the section belongs in the init part of the module */ +#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) + +// temp number, +#define VPE_MAJOR 63 + +static char module_name[] = "vpe"; +static int major = 0; + +/* grab the likely amount of memory we will need. */ +#ifdef CONFIG_MIPS_VPE_LOADER_TOM +#define P_SIZE (2 * 1024 * 1024) +#else +/* add an overhead to the max kmalloc size for non-striped symbols/etc */ +#define P_SIZE (256 * 1024) +#endif + +#define MAX_VPES 16 + +enum vpe_state { + VPE_STATE_UNUSED = 0, + VPE_STATE_INUSE, + VPE_STATE_RUNNING +}; + +enum tc_state { + TC_STATE_UNUSED = 0, + TC_STATE_INUSE, + TC_STATE_RUNNING, + TC_STATE_DYNAMIC +}; + +struct vpe; +typedef struct tc { + enum tc_state state; + int index; + + /* parent VPE */ + struct vpe *pvpe; + + /* The list of TC's with this VPE */ + struct list_head tc; + + /* The global list of tc's */ + struct list_head list; +} tc_t; + +typedef struct vpe { + enum vpe_state state; + + /* (device) minor associated with this vpe */ + int minor; + + /* elfloader stuff */ + void *load_addr; + u32 len; + char *pbuffer; + u32 plen; + + unsigned long __start; + + /* tc's associated with this vpe */ + struct list_head tc; + + /* The list of vpe's */ + struct list_head list; + + /* shared symbol address */ + void *shared_ptr; +} vpe_t; + +struct vpecontrol_ { + /* Virtual processing elements */ + struct list_head vpe_list; + + /* Thread contexts */ + struct list_head tc_list; +} vpecontrol; + +static void release_progmem(void *ptr); +static void dump_vpe(vpe_t * v); +extern void save_gp_address(unsigned int secbase, unsigned int rel); + +/* get the vpe associated with this minor */ +struct vpe *get_vpe(int minor) +{ + struct vpe *v; + + list_for_each_entry(v, &vpecontrol.vpe_list, list) { + if (v->minor == minor) + return v; + } + + printk(KERN_DEBUG "VPE: get_vpe minor %d not found\n", minor); + return NULL; +} + +/* get the vpe associated with this minor */ +struct tc *get_tc(int index) +{ + struct tc *t; + + list_for_each_entry(t, &vpecontrol.tc_list, list) { + if (t->index == index) + return t; + } + + printk(KERN_DEBUG "VPE: get_tc index %d not found\n", index); + + return NULL; +} + +struct tc *get_tc_unused(void) +{ + struct tc *t; + + list_for_each_entry(t, &vpecontrol.tc_list, list) { + if (t->state == TC_STATE_UNUSED) + return t; + } + + printk(KERN_DEBUG "VPE: All TC's are in use\n"); + + return NULL; +} + +/* allocate a vpe and associate it with this minor (or index) */ +struct vpe *alloc_vpe(int minor) +{ + struct vpe *v; + + if ((v = kmalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "VPE: alloc_vpe no mem\n"); + return NULL; + } + + memset(v, 0, sizeof(struct vpe)); + + INIT_LIST_HEAD(&v->tc); + list_add_tail(&v->list, &vpecontrol.vpe_list); + + v->minor = minor; + return v; +} + +/* allocate a tc. At startup only tc0 is running, all other can be halted. */ +struct tc *alloc_tc(int index) +{ + struct tc *t; + + if ((t = kmalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING "VPE: alloc_tc no mem\n"); + return NULL; + } + + memset(t, 0, sizeof(struct tc)); + + INIT_LIST_HEAD(&t->tc); + list_add_tail(&t->list, &vpecontrol.tc_list); + + t->index = index; + + return t; +} + +/* clean up and free everything */ +void release_vpe(struct vpe *v) +{ + list_del(&v->list); + if (v->load_addr) + release_progmem(v); + kfree(v); +} + +void dump_mtregs(void) +{ + unsigned long val; + + val = read_c0_config3(); + printk("config3 0x%lx MT %ld\n", val, + (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT); + + val = read_c0_mvpconf0(); + printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val, + (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT, + val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT); + + val = read_c0_mvpcontrol(); + printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val, + (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT, + (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT, + (val & MVPCONTROL_EVP)); + + val = read_c0_vpeconf0(); + printk("VPEConf0 0x%lx MVP %ld\n", val, + (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT); +} + +/* Find some VPE program space */ +static void *alloc_progmem(u32 len) +{ +#ifdef CONFIG_MIPS_VPE_LOADER_TOM + /* this means you must tell linux to use less memory than you physically have */ + return (void *)((max_pfn * PAGE_SIZE) + KSEG0); +#else + // simple grab some mem for now + return kmalloc(len, GFP_KERNEL); +#endif +} + +static void release_progmem(void *ptr) +{ +#ifndef CONFIG_MIPS_VPE_LOADER_TOM + kfree(ptr); +#endif +} + +/* Update size with this section: return offset. */ +static long get_offset(unsigned long *size, Elf_Shdr * sechdr) +{ + long ret; + + ret = ALIGN(*size, sechdr->sh_addralign ? : 1); + *size = ret + sechdr->sh_size; + return ret; +} + +/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld + might -- code, read-only data, read-write data, small data. Tally + sizes, and place the offsets into sh_entsize fields: high bit means it + belongs in init. */ +static void layout_sections(struct module *mod, const Elf_Ehdr * hdr, + Elf_Shdr * sechdrs, const char *secstrings) +{ + static unsigned long const masks[][2] = { + /* NOTE: all executable code must be the first section + * in this array; otherwise modify the text_size + * finder in the two loops below */ + {SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL}, + {SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL}, + {SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL}, + {ARCH_SHF_SMALL | SHF_ALLOC, 0} + }; + unsigned int m, i; + + for (i = 0; i < hdr->e_shnum; i++) + sechdrs[i].sh_entsize = ~0UL; + + for (m = 0; m < ARRAY_SIZE(masks); ++m) { + for (i = 0; i < hdr->e_shnum; ++i) { + Elf_Shdr *s = &sechdrs[i]; + + // || strncmp(secstrings + s->sh_name, ".init", 5) == 0) + if ((s->sh_flags & masks[m][0]) != masks[m][0] + || (s->sh_flags & masks[m][1]) + || s->sh_entsize != ~0UL) + continue; + s->sh_entsize = get_offset(&mod->core_size, s); + } + + if (m == 0) + mod->core_text_size = mod->core_size; + + } +} + + +/* from module-elf32.c, but subverted a little */ + +struct mips_hi16 { + struct mips_hi16 *next; + Elf32_Addr *addr; + Elf32_Addr value; +}; + +static struct mips_hi16 *mips_hi16_list; +static unsigned int gp_offs, gp_addr; + +static int apply_r_mips_none(struct module *me, uint32_t *location, + Elf32_Addr v) +{ + return 0; +} + +static int apply_r_mips_gprel16(struct module *me, uint32_t *location, + Elf32_Addr v) +{ + int rel; + + if( !(*location & 0xffff) ) { + rel = (int)v - gp_addr; + } + else { + /* .sbss + gp(relative) + offset */ + /* kludge! */ + rel = (int)(short)((int)v + gp_offs + + (int)(short)(*location & 0xffff) - gp_addr); + } + + if( (rel > 32768) || (rel < -32768) ) { + printk(KERN_ERR + "apply_r_mips_gprel16: relative address out of range 0x%x %d\n", + rel, rel); + return -ENOEXEC; + } + + *location = (*location & 0xffff0000) | (rel & 0xffff); + + return 0; +} + +static int apply_r_mips_pc16(struct module *me, uint32_t *location, + Elf32_Addr v) +{ + int rel; + rel = (((unsigned int)v - (unsigned int)location)); + rel >>= 2; // because the offset is in _instructions_ not bytes. + rel -= 1; // and one instruction less due to the branch delay slot. + + if( (rel > 32768) || (rel < -32768) ) { + printk(KERN_ERR + "apply_r_mips_pc16: relative address out of range 0x%x\n", rel); + return -ENOEXEC; + } + + *location = (*location & 0xffff0000) | (rel & 0xffff); + + return 0; +} + +static int apply_r_mips_32(struct module *me, uint32_t *location, + Elf32_Addr v) +{ + *location += v; + + return 0; +} + +static int apply_r_mips_26(struct module *me, uint32_t *location, + Elf32_Addr v) +{ + if (v % 4) { + printk(KERN_ERR "module %s: dangerous relocation mod4\n", me->name); + return -ENOEXEC; + } + +/* Not desperately convinced this is a good check of an overflow condition + anyway. But it gets in the way of handling undefined weak symbols which + we want to set to zero. + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { + printk(KERN_ERR + "module %s: relocation overflow\n", + me->name); + return -ENOEXEC; + } +*/ + + *location = (*location & ~0x03ffffff) | + ((*location + (v >> 2)) & 0x03ffffff); + return 0; +} + +static int apply_r_mips_hi16(struct module *me, uint32_t *location, + Elf32_Addr v) +{ + struct mips_hi16 *n; + + /* + * We cannot relocate this one now because we don't know the value of + * the carry we need to add. Save the information, and let LO16 do the + * actual relocation. + */ + n = kmalloc(sizeof *n, GFP_KERNEL); + if (!n) + return -ENOMEM; + + n->addr = location; + n->value = v; + n->next = mips_hi16_list; + mips_hi16_list = n; + + return 0; +} + +static int apply_r_mips_lo16(struct module *me, uint32_t *location, + Elf32_Addr v) +{ + unsigned long insnlo = *location; + Elf32_Addr val, vallo; + + /* Sign extend the addend we extract from the lo insn. */ + vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; + + if (mips_hi16_list != NULL) { + struct mips_hi16 *l; + + l = mips_hi16_list; + while (l != NULL) { + struct mips_hi16 *next; + unsigned long insn; + + /* + * The value for the HI16 had best be the same. + */ + if (v != l->value) { + printk("%d != %d\n", v, l->value); + goto out_danger; + } + + + /* + * Do the HI16 relocation. Note that we actually don't + * need to know anything about the LO16 itself, except + * where to find the low 16 bits of the addend needed + * by the LO16. + */ + insn = *l->addr; + val = ((insn & 0xffff) << 16) + vallo; + val += v; + + /* + * Account for the sign extension that will happen in + * the low bits. + */ + val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff; + + insn = (insn & ~0xffff) | val; + *l->addr = insn; + + next = l->next; + kfree(l); + l = next; + } + + mips_hi16_list = NULL; + } + + /* + * Ok, we're done with the HI16 relocs. Now deal with the LO16. + */ + val = v + vallo; + insnlo = (insnlo & ~0xffff) | (val & 0xffff); + *location = insnlo; + + return 0; + +out_danger: + printk(KERN_ERR "module %s: dangerous " "relocation\n", me->name); + + return -ENOEXEC; +} + +static int (*reloc_handlers[]) (struct module *me, uint32_t *location, + Elf32_Addr v) = { + [R_MIPS_NONE] = apply_r_mips_none, + [R_MIPS_32] = apply_r_mips_32, + [R_MIPS_26] = apply_r_mips_26, + [R_MIPS_HI16] = apply_r_mips_hi16, + [R_MIPS_LO16] = apply_r_mips_lo16, + [R_MIPS_GPREL16] = apply_r_mips_gprel16, + [R_MIPS_PC16] = apply_r_mips_pc16 +}; + + +int apply_relocations(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location; + unsigned int i; + Elf32_Addr v; + int res; + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + Elf32_Word r_info = rel[i].r_info; + + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset; + /* This is the symbol it is referring to */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(r_info); + + if (!sym->st_value) { + printk(KERN_DEBUG "%s: undefined weak symbol %s\n", + me->name, strtab + sym->st_name); + /* just print the warning, dont barf */ + } + + v = sym->st_value; + + res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v); + if( res ) { + printk(KERN_DEBUG + "relocation error 0x%x sym refer <%s> value 0x%x " + "type 0x%x r_info 0x%x\n", + (unsigned int)location, strtab + sym->st_name, v, + r_info, ELF32_R_TYPE(r_info)); + } + + if (res) + return res; + } + + return 0; +} + +void save_gp_address(unsigned int secbase, unsigned int rel) +{ + gp_addr = secbase + rel; + gp_offs = gp_addr - (secbase & 0xffff0000); +} +/* end module-elf32.c */ + + + +/* Change all symbols so that sh_value encodes the pointer directly. */ +static int simplify_symbols(Elf_Shdr * sechdrs, + unsigned int symindex, + const char *strtab, + const char *secstrings, + unsigned int nsecs, struct module *mod) +{ + Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; + unsigned long secbase, bssbase = 0; + unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); + int ret = 0, size; + + /* find the .bss section for COMMON symbols */ + for (i = 0; i < nsecs; i++) { + if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) + bssbase = sechdrs[i].sh_addr; + } + + for (i = 1; i < n; i++) { + switch (sym[i].st_shndx) { + case SHN_COMMON: + /* Allocate space for the symbol in the .bss section. st_value is currently size. + We want it to have the address of the symbol. */ + + size = sym[i].st_value; + sym[i].st_value = bssbase; + + bssbase += size; + break; + + case SHN_ABS: + /* Don't need to do anything */ + break; + + case SHN_UNDEF: + /* ret = -ENOENT; */ + break; + + case SHN_MIPS_SCOMMON: + + printk(KERN_DEBUG + "simplify_symbols: ignoring SHN_MIPS_SCOMMON symbol <%s> st_shndx %d\n", + strtab + sym[i].st_name, sym[i].st_shndx); + + // .sbss section + break; + + default: + secbase = sechdrs[sym[i].st_shndx].sh_addr; + + if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) { + save_gp_address(secbase, sym[i].st_value); + } + + sym[i].st_value += secbase; + break; + } + + } + + return ret; +} + +#ifdef DEBUG_ELFLOADER +static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex, + const char *strtab, struct module *mod) +{ + Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; + unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); + + printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n); + for (i = 1; i < n; i++) { + printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i, + strtab + sym[i].st_name, sym[i].st_value); + } +} +#endif + +static void dump_tc(struct tc *t) +{ + printk(KERN_WARNING "VPE: TC index %d TCStatus 0x%lx halt 0x%lx\n", + t->index, read_tc_c0_tcstatus(), read_tc_c0_tchalt()); + printk(KERN_WARNING "VPE: tcrestart 0x%lx\n", read_tc_c0_tcrestart()); +} + +static void dump_tclist(void) +{ + struct tc *t; + + list_for_each_entry(t, &vpecontrol.tc_list, list) { + dump_tc(t); + } +} + +/* We are prepared so configure and start the VPE... */ +int vpe_run(vpe_t * v) +{ + unsigned long val; + struct tc *t; + + /* check we are the Master VPE */ + val = read_c0_vpeconf0(); + if (!(val & VPECONF0_MVP)) { + printk(KERN_WARNING + "VPE: only Master VPE's are allowed to configure MT\n"); + return -1; + } + + /* disable MT (using dvpe) */ + dvpe(); + + /* Put MVPE's into 'configuration state' */ + write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); + + if (!list_empty(&v->tc)) { + if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { + printk(KERN_WARNING "VPE: TC %d is already in use.\n", + t->index); + return -ENOEXEC; + } + } else { + printk(KERN_WARNING "VPE: No TC's associated with VPE %d\n", + v->minor); + return -ENOEXEC; + } + + settc(t->index); + + val = read_vpe_c0_vpeconf0(); + + /* should check it is halted, and not activated */ + if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { + printk(KERN_WARNING "VPE: TC %d is already doing something!\n", + t->index); + + dump_tclist(); + return -ENOEXEC; + } + + /* Write the address we want it to start running from in the TCPC register. */ + write_tc_c0_tcrestart((unsigned long)v->__start); + + /* write the sivc_info address to tccontext */ + write_tc_c0_tccontext((unsigned long)0); + + /* Set up the XTC bit in vpeconf0 to point at our tc */ + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (t->index << VPECONF0_XTC_SHIFT)); + + /* mark the TC as activated, not interrupt exempt and not dynamically allocatable */ + val = read_tc_c0_tcstatus(); + val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A; + write_tc_c0_tcstatus(val); + + write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); + + /* set up VPE1 */ + write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); // no multiple TC's + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); // enable this VPE + + /* + * The sde-kit passes 'memsize' to __start in $a3, so set something + * here... + * Or set $a3 (register 7) to zero and define DFLT_STACK_SIZE and + * DFLT_HEAP_SIZE when you compile your program + */ + + mttgpr(7, 0); + + /* set config to be the same as vpe0, particularly kseg0 coherency alg */ + write_vpe_c0_config(read_c0_config()); + + /* clear out any left overs from a previous program */ + write_vpe_c0_cause(0); + + /* take system out of configuration state */ + write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); + + /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */ + write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE | ST0_EXL)); + + /* set it running */ + evpe(EVPE_ENABLE); + + return 0; +} + +static unsigned long find_vpe_symbols(vpe_t * v, Elf_Shdr * sechdrs, + unsigned int symindex, const char *strtab, + struct module *mod) +{ + Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; + unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); + + for (i = 1; i < n; i++) { + if (strcmp(strtab + sym[i].st_name, "__start") == 0) { + v->__start = sym[i].st_value; + } + + if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) { + v->shared_ptr = (void *)sym[i].st_value; + } + } + + return 0; +} + +/* Allocates a VPE with some program code space(the load address), copies the contents + of the program (p)buffer performing relocatations/etc, free's it when finished. +*/ +int vpe_elfload(vpe_t * v) +{ + Elf_Ehdr *hdr; + Elf_Shdr *sechdrs; + long err = 0; + char *secstrings, *strtab = NULL; + unsigned int len, i, symindex = 0, strindex = 0; + + struct module mod; // so we can re-use the relocations code + + memset(&mod, 0, sizeof(struct module)); + strcpy(mod.name, "VPE dummy prog module"); + + hdr = (Elf_Ehdr *) v->pbuffer; + len = v->plen; + + /* Sanity checks against insmoding binaries or wrong arch, + weird elf version */ + if (memcmp(hdr->e_ident, ELFMAG, 4) != 0 + || hdr->e_type != ET_REL || !elf_check_arch(hdr) + || hdr->e_shentsize != sizeof(*sechdrs)) { + printk(KERN_WARNING + "VPE program, wrong arch or weird elf version\n"); + + return -ENOEXEC; + } + + if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) { + printk(KERN_ERR "VPE program length %u truncated\n", len); + return -ENOEXEC; + } + + /* Convenience variables */ + sechdrs = (void *)hdr + hdr->e_shoff; + secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + sechdrs[0].sh_addr = 0; + + /* And these should exist, but gcc whinges if we don't init them */ + symindex = strindex = 0; + + for (i = 1; i < hdr->e_shnum; i++) { + + if (sechdrs[i].sh_type != SHT_NOBITS + && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) { + printk(KERN_ERR "VPE program length %u truncated\n", + len); + return -ENOEXEC; + } + + /* Mark all sections sh_addr with their address in the + temporary image. */ + sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset; + + /* Internal symbols and strings. */ + if (sechdrs[i].sh_type == SHT_SYMTAB) { + symindex = i; + strindex = sechdrs[i].sh_link; + strtab = (char *)hdr + sechdrs[strindex].sh_offset; + } + } + + layout_sections(&mod, hdr, sechdrs, secstrings); + + v->load_addr = alloc_progmem(mod.core_size); + memset(v->load_addr, 0, mod.core_size); + + printk("VPE elf_loader: loading to %p\n", v->load_addr); + + for (i = 0; i < hdr->e_shnum; i++) { + void *dest; + + if (!(sechdrs[i].sh_flags & SHF_ALLOC)) + continue; + + dest = v->load_addr + sechdrs[i].sh_entsize; + + if (sechdrs[i].sh_type != SHT_NOBITS) + memcpy(dest, (void *)sechdrs[i].sh_addr, + sechdrs[i].sh_size); + /* Update sh_addr to point to copy in image. */ + sechdrs[i].sh_addr = (unsigned long)dest; + } + + /* Fix up syms, so that st_value is a pointer to location. */ + err = + simplify_symbols(sechdrs, symindex, strtab, secstrings, + hdr->e_shnum, &mod); + if (err < 0) { + printk(KERN_WARNING "VPE: unable to simplify symbols\n"); + goto cleanup; + } + + /* Now do relocations. */ + for (i = 1; i < hdr->e_shnum; i++) { + const char *strtab = (char *)sechdrs[strindex].sh_addr; + unsigned int info = sechdrs[i].sh_info; + + /* Not a valid relocation section? */ + if (info >= hdr->e_shnum) + continue; + + /* Don't bother with non-allocated sections */ + if (!(sechdrs[info].sh_flags & SHF_ALLOC)) + continue; + + if (sechdrs[i].sh_type == SHT_REL) + err = + apply_relocations(sechdrs, strtab, symindex, i, &mod); + else if (sechdrs[i].sh_type == SHT_RELA) + err = apply_relocate_add(sechdrs, strtab, symindex, i, + &mod); + if (err < 0) { + printk(KERN_WARNING + "vpe_elfload: error in relocations err %ld\n", + err); + goto cleanup; + } + } + + /* make sure it's physically written out */ + flush_icache_range((unsigned long)v->load_addr, + (unsigned long)v->load_addr + v->len); + + if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { + + printk(KERN_WARNING + "VPE: program doesn't contain __start or vpe_shared symbols\n"); + err = -ENOEXEC; + } + + printk(" elf loaded\n"); + +cleanup: + return err; +} + +static void dump_vpe(vpe_t * v) +{ + struct tc *t; + + printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol()); + printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0()); + + list_for_each_entry(t, &vpecontrol.tc_list, list) { + dump_tc(t); + } +} + +/* checks for VPE is unused and gets ready to load program */ +static int vpe_open(struct inode *inode, struct file *filp) +{ + int minor; + vpe_t *v; + + /* assume only 1 device at the mo. */ + if ((minor = MINOR(inode->i_rdev)) != 1) { + printk(KERN_WARNING "VPE: only vpe1 is supported\n"); + return -ENODEV; + } + + if ((v = get_vpe(minor)) == NULL) { + printk(KERN_WARNING "VPE: unable to get vpe\n"); + return -ENODEV; + } + + if (v->state != VPE_STATE_UNUSED) { + unsigned long tmp; + struct tc *t; + + printk(KERN_WARNING "VPE: device %d already in use\n", minor); + + dvpe(); + dump_vpe(v); + + printk(KERN_WARNING "VPE: re-initialising %d\n", minor); + + release_progmem(v->load_addr); + + t = get_tc(minor); + settc(minor); + tmp = read_tc_c0_tcstatus(); + + /* mark not allocated and not dynamically allocatable */ + tmp &= ~(TCSTATUS_A | TCSTATUS_DA); + tmp |= TCSTATUS_IXMT; /* interrupt exempt */ + write_tc_c0_tcstatus(tmp); + + write_tc_c0_tchalt(TCHALT_H); + + } + + // allocate it so when we get write ops we know it's expected. + v->state = VPE_STATE_INUSE; + + /* this of-course trashes what was there before... */ + v->pbuffer = vmalloc(P_SIZE); + v->plen = P_SIZE; + v->load_addr = NULL; + v->len = 0; + + return 0; +} + +static int vpe_release(struct inode *inode, struct file *filp) +{ + int minor, ret = 0; + vpe_t *v; + Elf_Ehdr *hdr; + + minor = MINOR(inode->i_rdev); + if ((v = get_vpe(minor)) == NULL) + return -ENODEV; + + // simple case of fire and forget, so tell the VPE to run... + + hdr = (Elf_Ehdr *) v->pbuffer; + if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) { + if (vpe_elfload(v) >= 0) + vpe_run(v); + else { + printk(KERN_WARNING "VPE: ELF load failed.\n"); + ret = -ENOEXEC; + } + } else { + printk(KERN_WARNING "VPE: only elf files are supported\n"); + ret = -ENOEXEC; + } + + // cleanup any temp buffers + if (v->pbuffer) + vfree(v->pbuffer); + v->plen = 0; + return ret; +} + +static ssize_t vpe_write(struct file *file, const char __user * buffer, + size_t count, loff_t * ppos) +{ + int minor; + size_t ret = count; + vpe_t *v; + + minor = MINOR(file->f_dentry->d_inode->i_rdev); + if ((v = get_vpe(minor)) == NULL) + return -ENODEV; + + if (v->pbuffer == NULL) { + printk(KERN_ERR "vpe_write: no pbuffer\n"); + return -ENOMEM; + } + + if ((count + v->len) > v->plen) { + printk(KERN_WARNING + "VPE Loader: elf size too big. Perhaps strip uneeded symbols\n"); + return -ENOMEM; + } + + count -= copy_from_user(v->pbuffer + v->len, buffer, count); + if (!count) { + printk("vpe_write: copy_to_user failed\n"); + return -EFAULT; + } + + v->len += count; + return ret; +} + +static struct file_operations vpe_fops = { + .owner = THIS_MODULE, + .open = vpe_open, + .release = vpe_release, + .write = vpe_write +}; + +/* module wrapper entry points */ +/* give me a vpe */ +vpe_handle vpe_alloc(void) +{ + int i; + struct vpe *v; + + /* find a vpe */ + for (i = 1; i < MAX_VPES; i++) { + if ((v = get_vpe(i)) != NULL) { + v->state = VPE_STATE_INUSE; + return v; + } + } + return NULL; +} + +EXPORT_SYMBOL(vpe_alloc); + +/* start running from here */ +int vpe_start(vpe_handle vpe, unsigned long start) +{ + struct vpe *v = vpe; + + v->__start = start; + return vpe_run(v); +} + +EXPORT_SYMBOL(vpe_start); + +/* halt it for now */ +int vpe_stop(vpe_handle vpe) +{ + struct vpe *v = vpe; + struct tc *t; + unsigned int evpe_flags; + + evpe_flags = dvpe(); + + if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) { + + settc(t->index); + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); + } + + evpe(evpe_flags); + + return 0; +} + +EXPORT_SYMBOL(vpe_stop); + +/* I've done with it thank you */ +int vpe_free(vpe_handle vpe) +{ + struct vpe *v = vpe; + struct tc *t; + unsigned int evpe_flags; + + if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { + return -ENOEXEC; + } + + evpe_flags = dvpe(); + + /* Put MVPE's into 'configuration state' */ + write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); + + settc(t->index); + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); + + /* mark the TC unallocated and halt'ed */ + write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A); + write_tc_c0_tchalt(TCHALT_H); + + v->state = VPE_STATE_UNUSED; + + write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); + evpe(evpe_flags); + + return 0; +} + +EXPORT_SYMBOL(vpe_free); + +void *vpe_get_shared(int index) +{ + struct vpe *v; + + if ((v = get_vpe(index)) == NULL) { + printk(KERN_WARNING "vpe: invalid vpe index %d\n", index); + return NULL; + } + + return v->shared_ptr; +} + +EXPORT_SYMBOL(vpe_get_shared); + +static int __init vpe_module_init(void) +{ + struct vpe *v = NULL; + struct tc *t; + unsigned long val; + int i; + + if (!cpu_has_mipsmt) { + printk("VPE loader: not a MIPS MT capable processor\n"); + return -ENODEV; + } + + if ((major = register_chrdev(VPE_MAJOR, module_name, &vpe_fops) < 0)) { + printk("VPE loader: unable to register character device\n"); + return -EBUSY; + } + + if (major == 0) + major = VPE_MAJOR; + + dmt(); + dvpe(); + + /* Put MVPE's into 'configuration state' */ + write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); + + /* dump_mtregs(); */ + + INIT_LIST_HEAD(&vpecontrol.vpe_list); + INIT_LIST_HEAD(&vpecontrol.tc_list); + + val = read_c0_mvpconf0(); + for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) { + t = alloc_tc(i); + + /* VPE's */ + if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) { + settc(i); + + if ((v = alloc_vpe(i)) == NULL) { + printk(KERN_WARNING "VPE: unable to allocate VPE\n"); + return -ENODEV; + } + + list_add(&t->tc, &v->tc); /* add the tc to the list of this vpe's tc's. */ + + /* deactivate all but vpe0 */ + if (i != 0) { + unsigned long tmp = read_vpe_c0_vpeconf0(); + + tmp &= ~VPECONF0_VPA; + + /* master VPE */ + tmp |= VPECONF0_MVP; + write_vpe_c0_vpeconf0(tmp); + } + + /* disable multi-threading with TC's */ + write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); + + if (i != 0) { + write_vpe_c0_status((read_c0_status() & + ~(ST0_IM | ST0_IE | ST0_KSU)) + | ST0_CU0); + + /* set config to be the same as vpe0, particularly kseg0 coherency alg */ + write_vpe_c0_config(read_c0_config()); + } + + } + + /* TC's */ + t->pvpe = v; /* set the parent vpe */ + + if (i != 0) { + unsigned long tmp; + + /* tc 0 will of course be running.... */ + if (i == 0) + t->state = TC_STATE_RUNNING; + + settc(i); + + /* bind a TC to each VPE, May as well put all excess TC's + on the last VPE */ + if (i >= (((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1)) + write_tc_c0_tcbind(read_tc_c0_tcbind() | + ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)); + else + write_tc_c0_tcbind(read_tc_c0_tcbind() | i); + + tmp = read_tc_c0_tcstatus(); + + /* mark not allocated and not dynamically allocatable */ + tmp &= ~(TCSTATUS_A | TCSTATUS_DA); + tmp |= TCSTATUS_IXMT; /* interrupt exempt */ + write_tc_c0_tcstatus(tmp); + + write_tc_c0_tchalt(TCHALT_H); + } + } + + /* release config state */ + write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); + + return 0; +} + +static void __exit vpe_module_exit(void) +{ + struct vpe *v, *n; + + list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) { + if (v->state != VPE_STATE_UNUSED) { + release_vpe(v); + } + } + + unregister_chrdev(major, module_name); +} + +module_init(vpe_module_init); +module_exit(vpe_module_exit); +MODULE_DESCRIPTION("MIPS VPE Loader"); +MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From bdf21b18b4abf983db38f04ef7fec88f47389867 Mon Sep 17 00:00:00 2001 From: Pete Popov Date: Thu, 14 Jul 2005 17:47:57 +0000 Subject: Philips PNX8550 support: MIPS32-like core with 2 Trimedias on it. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 19 +++++++++++++++++++ arch/mips/kernel/proc.c | 3 ++- arch/mips/kernel/time.c | 3 +++ 3 files changed, 24 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 844126b39ed..70c8ad9bc8f 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -121,6 +121,7 @@ static inline void check_wait(void) case CPU_24K: case CPU_25KF: case CPU_34K: + case CPU_PR4450: cpu_wait = r4k_wait; printk(" available.\n"); break; @@ -624,6 +625,21 @@ static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c) } } +static inline void cpu_probe_philips(struct cpuinfo_mips *c) +{ + decode_configs(c); + switch (c->processor_id & 0xff00) { + case PRID_IMP_PR4450: + c->cputype = CPU_PR4450; + c->isa_level = MIPS_CPU_ISA_M32; + break; + default: + panic("Unknown Philips Core!"); /* REVISIT: die? */ + break; + } +} + + __init void cpu_probe(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -649,6 +665,9 @@ __init void cpu_probe(void) case PRID_COMP_SANDCRAFT: cpu_probe_sandcraft(c); break; + case PRID_COMP_PHILIPS: + cpu_probe_philips(c); + break; default: c->cputype = CPU_UNKNOWN; } diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 1bd40af508e..e46a92d01d5 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -80,7 +80,8 @@ static const char *cpu_name[] = { [CPU_VR4133] = "NEC VR4133", [CPU_VR4181] = "NEC VR4181", [CPU_VR4181A] = "NEC VR4181A", - [CPU_SR71000] = "Sandcraft SR71000" + [CPU_SR71000] = "Sandcraft SR71000", + [CPU_PR4450] = "Philips PR4450", }; diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index fbc153c8f83..a24651dfaab 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -11,6 +11,7 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ +#include #include #include #include @@ -112,8 +113,10 @@ static void c0_timer_ack(void) { unsigned int count; +#ifndef CONFIG_SOC_PNX8550 /* pnx8550 resets to zero */ /* Ack this timer interrupt and set the next one. */ expirelo += cycles_per_jiffy; +#endif write_c0_compare(expirelo); /* Check to see if we have missed any timer interrupts. */ -- cgit v1.2.3 From 1d40cfcd3442a53e98468cdb3e6d4d9a568d76cf Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 15 Jul 2005 15:23:23 +0000 Subject: Avoid SMP cacheflushes. This is a minor optimization of startup but will also avoid smp_call_function from doing stupid things when called from a CPU that is not yet marked online. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 0a3969aa8dc..519b8f18eed 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1150,6 +1150,7 @@ static inline void signal32_init(void) extern void cpu_cache_init(void); extern void tlb_init(void); +extern void flush_tlb_handlers(void); void __init per_cpu_trap_init(void) { @@ -1348,4 +1349,5 @@ void __init trap_init(void) #endif flush_icache_range(ebase, ebase + 0x400); + flush_tlb_handlers(); } -- cgit v1.2.3 From ae1b3d51c89a96c641111e2c103557592577cf51 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 15 Jul 2005 15:44:02 +0000 Subject: Make sure that the processor is actually online or die spectacularly. Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 25762917e82..798fce50939 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -142,6 +142,11 @@ int smp_call_function (void (*func) (void *info), void *info, int retry, int i, cpus = num_online_cpus() - 1; int cpu = smp_processor_id(); + /* + * Can die spectacularly if this CPU isn't yet marked online + */ + BUG_ON(!cpu_online(cpu)); + if (!cpus) return 0; -- cgit v1.2.3 From 075e7502d9701dbc206ed32046888acfc8a4bb73 Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Wed, 27 Jul 2005 21:48:12 +0000 Subject: R4600 has 32 FPRs. Signed-off-by: Thiemo Seufer Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 70c8ad9bc8f..5d71eca4157 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -277,7 +277,8 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c) case PRID_IMP_R4600: c->cputype = CPU_R4600; c->isa_level = MIPS_CPU_ISA_III; - c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC; + c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR | + MIPS_CPU_LLSC; c->tlbsize = 48; break; #if 0 -- cgit v1.2.3 From 8d9c62675d58ebfb7dfce64cd1ce109e7d90af87 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 5 Aug 2005 10:31:47 +0000 Subject: sys is only used for native o32 ... Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall64-n32.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 0dfb34bf979..b32c566e0a2 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -364,6 +364,6 @@ EXPORT(sysn32_call_table) PTR sys_request_key PTR sys_keyctl /* 6245 */ PTR sys_set_thread_area - sys sys_inotify_init - sys sys_inotify_add_watch - sys sys_inotify_rm_watch + PTR sys_inotify_init + PTR sys_inotify_add_watch + PTR sys_inotify_rm_watch -- cgit v1.2.3 From d9912d87840b321678c85396c6adf15ced2c228d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 9 Aug 2005 15:23:49 +0000 Subject: Inlining will result in back-to-back mtc0 mfc0 instructions. Break the hazard by using back_to_back_c0_hazard(). Signed-off-by: Ralf Baechle --- arch/mips/kernel/irq_cpu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 060722e42c5..31c38c4971c 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -55,6 +55,7 @@ static inline void mips_cpu_irq_enable(unsigned int irq) local_irq_save(flags); unmask_mips_irq(irq); + back_to_back_c0_hazard(); local_irq_restore(flags); } @@ -64,6 +65,7 @@ static void mips_cpu_irq_disable(unsigned int irq) local_irq_save(flags); mask_mips_irq(irq); + back_to_back_c0_hazard(); local_irq_restore(flags); } -- cgit v1.2.3 From 28a7879d8ca6afafbd1583dd777587e441d0f90e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 16 Aug 2005 15:46:05 +0000 Subject: Spelling fix. Signed-off-by: Ralf Baechle --- arch/mips/kernel/i8259.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index a7d2aac46ee..911537413b6 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -307,7 +307,7 @@ static struct resource pic2_io_resource = { /* * On systems with i8259-style interrupt controllers we assume for - * driver compatibility reasons interrupts 0 - 15 to be the i8295 + * driver compatibility reasons interrupts 0 - 15 to be the i8259 * interrupts even if the hardware uses a different interrupt numbering. */ void __init init_i8259_irqs (void) -- cgit v1.2.3 From 3bffe736d93ce527a27fd5a4845fb2a0e82fcd99 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 16 Aug 2005 16:10:18 +0000 Subject: Delete old junk. Signed-off-by: Ralf Baechle --- arch/mips/kernel/smp.c | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 798fce50939..fcacf1aae98 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -50,7 +50,6 @@ static void smp_tune_scheduling (void) { struct cache_desc *cd = ¤t_cpu_data.scache; unsigned long cachesize; /* kB */ - unsigned long bandwidth = 350; /* MB/s */ unsigned long cpu_khz; /* -- cgit v1.2.3 From e027802e985f1cca752bf3b2e7eecae05031699f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 16 Aug 2005 16:39:15 +0000 Subject: Display presence of SmartMIPS, DSP and MT ASEs in /proc/cpuinfo. Signed-off-by: Ralf Baechle --- arch/mips/kernel/proc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index e46a92d01d5..f2b0446e44b 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -121,11 +121,14 @@ static int show_cpuinfo(struct seq_file *m, void *v) cpu_has_divec ? "yes" : "no"); seq_printf(m, "hardware watchpoint\t: %s\n", cpu_has_watch ? "yes" : "no"); - seq_printf(m, "ASEs implemented\t:%s%s%s%s\n", + seq_printf(m, "ASEs implemented\t:%s%s%s%s%s%s\n", cpu_has_mips16 ? " mips16" : "", cpu_has_mdmx ? " mdmx" : "", cpu_has_mips3d ? " mips3d" : "", - cpu_has_smartmips ? " smartmips" : ""); + cpu_has_smartmips ? " smartmips" : "", + cpu_has_dsp ? " dsp" : "", + cpu_has_mipsmt ? " mt" : "" + ); sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", cpu_has_vce ? "%u" : "not available"); -- cgit v1.2.3 From d03d0a57754cb820d318d2234c60b728eb38a94d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 17 Aug 2005 13:44:26 +0000 Subject: MT bulletproofing. Signed-off-by: Ralf Baechle --- arch/mips/kernel/irq_cpu.c | 79 +++++++++++++++++++++++++++++++++++++++------- arch/mips/kernel/traps.c | 10 ++++-- 2 files changed, 75 insertions(+), 14 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 31c38c4971c..5db67e31ec1 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c @@ -33,6 +33,7 @@ #include #include +#include #include static int mips_cpu_irq_base; @@ -76,7 +77,7 @@ static unsigned int mips_cpu_irq_startup(unsigned int irq) return 0; } -#define mips_cpu_irq_shutdown mips_cpu_irq_disable +#define mips_cpu_irq_shutdown mips_cpu_irq_disable /* * While we ack the interrupt interrupts are disabled and thus we don't need @@ -84,9 +85,6 @@ static unsigned int mips_cpu_irq_startup(unsigned int irq) */ static void mips_cpu_irq_ack(unsigned int irq) { - /* Only necessary for soft interrupts */ - clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); - mask_mips_irq(irq); } @@ -97,15 +95,60 @@ static void mips_cpu_irq_end(unsigned int irq) } static hw_irq_controller mips_cpu_irq_controller = { - .typename = "MIPS", - .startup = mips_cpu_irq_startup, - .shutdown = mips_cpu_irq_shutdown, - .enable = mips_cpu_irq_enable, - .disable = mips_cpu_irq_disable, - .ack = mips_cpu_irq_ack, - .end = mips_cpu_irq_end, + .typename = "MIPS", + .startup = mips_cpu_irq_startup, + .shutdown = mips_cpu_irq_shutdown, + .enable = mips_cpu_irq_enable, + .disable = mips_cpu_irq_disable, + .ack = mips_cpu_irq_ack, + .end = mips_cpu_irq_end, }; +/* + * Basically the same as above but taking care of all the MT stuff + */ + +#define unmask_mips_mt_irq unmask_mips_irq +#define mask_mips_mt_irq mask_mips_irq +#define mips_mt_cpu_irq_enable mips_cpu_irq_enable +#define mips_mt_cpu_irq_disable mips_cpu_irq_disable + +static unsigned int mips_mt_cpu_irq_startup(unsigned int irq) +{ + unsigned int vpflags = dvpe(); + + clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); + evpe(vpflags); + mips_mt_cpu_irq_enable(irq); + + return 0; +} + +#define mips_mt_cpu_irq_shutdown mips_mt_cpu_irq_disable + +/* + * While we ack the interrupt interrupts are disabled and thus we don't need + * to deal with concurrency issues. Same for mips_cpu_irq_end. + */ +static void mips_mt_cpu_irq_ack(unsigned int irq) +{ + unsigned int vpflags = dvpe(); + clear_c0_cause(0x100 << (irq - mips_cpu_irq_base)); + evpe(vpflags); + mask_mips_mt_irq(irq); +} + +#define mips_mt_cpu_irq_end mips_cpu_irq_end + +static hw_irq_controller mips_mt_cpu_irq_controller = { + .typename = "MIPS", + .startup = mips_mt_cpu_irq_startup, + .shutdown = mips_mt_cpu_irq_shutdown, + .enable = mips_mt_cpu_irq_enable, + .disable = mips_mt_cpu_irq_disable, + .ack = mips_mt_cpu_irq_ack, + .end = mips_mt_cpu_irq_end, +}; void __init mips_cpu_irq_init(int irq_base) { @@ -115,7 +158,19 @@ void __init mips_cpu_irq_init(int irq_base) clear_c0_status(ST0_IM); clear_c0_cause(CAUSEF_IP); - for (i = irq_base; i < irq_base + 8; i++) { + /* + * Only MT is using the software interrupts currently, so we just + * leave them uninitialized for other processors. + */ + if (cpu_has_mipsmt) + for (i = irq_base; i < irq_base + 2; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &mips_mt_cpu_irq_controller; + } + + for (i = irq_base + 2; i < irq_base + 8; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = NULL; irq_desc[i].depth = 1; diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 519b8f18eed..876aff71cd2 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1186,8 +1186,14 @@ void __init per_cpu_trap_init(void) /* Setting vector spacing enables EI/VI mode */ change_c0_intctl (0x3e0, VECTORSPACING); } - if (cpu_has_divec) - set_c0_cause(CAUSEF_IV); + if (cpu_has_divec) { + if (cpu_has_mipsmt) { + unsigned int vpflags = dvpe(); + set_c0_cause(CAUSEF_IV); + evpe(vpflags); + } else + set_c0_cause(CAUSEF_IV); + } cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; TLBMISS_HANDLER_SETUP(); -- cgit v1.2.3 From 340ee4b98c0543b5632cac975a7449a2d28762d8 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 17 Aug 2005 17:44:08 +0000 Subject: Virtual SMP support for the 34K. Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 2 + arch/mips/kernel/genex.S | 1 + arch/mips/kernel/smp_mt.c | 366 ++++++++++++++++++++++++++++++++++++++++++++++ arch/mips/kernel/traps.c | 14 ++ arch/mips/kernel/vpe.c | 15 +- 5 files changed, 391 insertions(+), 7 deletions(-) create mode 100644 arch/mips/kernel/smp_mt.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 0f527063a8a..4c09e1acafd 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -34,6 +34,8 @@ obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_MIPS_MT_SMP) += smp_mt.o + obj-$(CONFIG_MIPS_VPE_LOADER) += vpe.o obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index fd904d1e419..aa18a8b7b38 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -323,6 +323,7 @@ NESTED(nmi_handler, PT_SIZE, sp) BUILD_HANDLER mdmx mdmx sti silent /* #22 */ BUILD_HANDLER watch watch sti verbose /* #23 */ BUILD_HANDLER mcheck mcheck cli verbose /* #24 */ + BUILD_HANDLER mt mt sti verbose /* #25 */ BUILD_HANDLER dsp dsp sti silent /* #26 */ BUILD_HANDLER reserved reserved sti verbose /* others */ diff --git a/arch/mips/kernel/smp_mt.c b/arch/mips/kernel/smp_mt.c new file mode 100644 index 00000000000..d429544ba4b --- /dev/null +++ b/arch/mips/kernel/smp_mt.c @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. + * + * Elizabeth Clarke (beth@mips.com) + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MIPS_CPU_IPI_RESCHED_IRQ 0 +#define MIPS_CPU_IPI_CALL_IRQ 1 + +static int cpu_ipi_resched_irq, cpu_ipi_call_irq; + +#if 0 +static void dump_mtregisters(int vpe, int tc) +{ + printk("vpe %d tc %d\n", vpe, tc); + + settc(tc); + + printk(" c0 status 0x%lx\n", read_vpe_c0_status()); + printk(" vpecontrol 0x%lx\n", read_vpe_c0_vpecontrol()); + printk(" vpeconf0 0x%lx\n", read_vpe_c0_vpeconf0()); + printk(" tcstatus 0x%lx\n", read_tc_c0_tcstatus()); + printk(" tcrestart 0x%lx\n", read_tc_c0_tcrestart()); + printk(" tcbind 0x%lx\n", read_tc_c0_tcbind()); + printk(" tchalt 0x%lx\n", read_tc_c0_tchalt()); +} +#endif + +void __init sanitize_tlb_entries(void) +{ + int i, tlbsiz; + unsigned long mvpconf0, ncpu; + + if (!cpu_has_mipsmt) + return; + + set_c0_mvpcontrol(MVPCONTROL_VPC); + + /* Disable TLB sharing */ + clear_c0_mvpcontrol(MVPCONTROL_STLB); + + mvpconf0 = read_c0_mvpconf0(); + + printk(KERN_INFO "MVPConf0 0x%lx TLBS %lx PTLBE %ld\n", mvpconf0, + (mvpconf0 & MVPCONF0_TLBS) >> MVPCONF0_TLBS_SHIFT, + (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT); + + tlbsiz = (mvpconf0 & MVPCONF0_PTLBE) >> MVPCONF0_PTLBE_SHIFT; + ncpu = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; + + printk(" tlbsiz %d ncpu %ld\n", tlbsiz, ncpu); + + if (tlbsiz > 0) { + /* share them out across the vpe's */ + tlbsiz /= ncpu; + + printk(KERN_INFO "setting Config1.MMU_size to %d\n", tlbsiz); + + for (i = 0; i < ncpu; i++) { + settc(i); + + if (i == 0) + write_c0_config1((read_c0_config1() & ~(0x3f << 25)) | (tlbsiz << 25)); + else + write_vpe_c0_config1((read_vpe_c0_config1() & ~(0x3f << 25)) | + (tlbsiz << 25)); + } + } + + clear_c0_mvpcontrol(MVPCONTROL_VPC); +} + +#if 0 +/* + * Use c0_MVPConf0 to find out how many CPUs are available, setting up + * phys_cpu_present_map and the logical/physical mappings. + */ +void __init prom_build_cpu_map(void) +{ + int i, num, ncpus; + + cpus_clear(phys_cpu_present_map); + + /* assume we boot on cpu 0.... */ + cpu_set(0, phys_cpu_present_map); + __cpu_number_map[0] = 0; + __cpu_logical_map[0] = 0; + + if (cpu_has_mipsmt) { + ncpus = ((read_c0_mvpconf0() & (MVPCONF0_PVPE)) >> MVPCONF0_PVPE_SHIFT) + 1; + for (i=1, num=0; i< NR_CPUS && i> MVPCONF0_PTC_SHIFT); i++) { + settc(i); + + /* VPE's */ + if (i <= ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)) { + + /* deactivate all but vpe0 */ + if (i != 0) { + unsigned long tmp = read_vpe_c0_vpeconf0(); + + tmp &= ~VPECONF0_VPA; + + /* master VPE */ + tmp |= VPECONF0_MVP; + write_vpe_c0_vpeconf0(tmp); + + /* Record this as available CPU */ + if (i < max_cpus) { + cpu_set(i, phys_cpu_present_map); + __cpu_number_map[i] = ++num; + __cpu_logical_map[num] = i; + } + } + + /* disable multi-threading with TC's */ + write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); + + if (i != 0) { + write_vpe_c0_status((read_c0_status() & ~(ST0_IM | ST0_IE | ST0_KSU)) | ST0_CU0); + write_vpe_c0_cause(read_vpe_c0_cause() & ~CAUSEF_IP); + + /* set config to be the same as vpe0, particularly kseg0 coherency alg */ + write_vpe_c0_config( read_c0_config()); + } + + } + + /* TC's */ + + if (i != 0) { + unsigned long tmp; + + /* bind a TC to each VPE, May as well put all excess TC's + on the last VPE */ + if ( i >= (((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT)+1) ) + write_tc_c0_tcbind(read_tc_c0_tcbind() | ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) ); + else { + write_tc_c0_tcbind( read_tc_c0_tcbind() | i); + + /* and set XTC */ + write_vpe_c0_vpeconf0( read_vpe_c0_vpeconf0() | (i << VPECONF0_XTC_SHIFT)); + } + + tmp = read_tc_c0_tcstatus(); + + /* mark not allocated and not dynamically allocatable */ + tmp &= ~(TCSTATUS_A | TCSTATUS_DA); + tmp |= TCSTATUS_IXMT; /* interrupt exempt */ + write_tc_c0_tcstatus(tmp); + + write_tc_c0_tchalt(TCHALT_H); + } + } + + /* Release config state */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); + + /* We'll wait until starting the secondaries before starting MVPE */ + + printk(KERN_INFO "Detected %i available secondary CPU(s)\n", num); + + /* set up ipi interrupts */ + if (cpu_has_vint) { + set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch); + set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch); + } + + cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ; + cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ; + + setup_irq(cpu_ipi_resched_irq, &irq_resched); + setup_irq(cpu_ipi_call_irq, &irq_call); + + /* need to mark IPI's as IRQ_PER_CPU */ + irq_desc[cpu_ipi_resched_irq].status |= IRQ_PER_CPU; + irq_desc[cpu_ipi_call_irq].status |= IRQ_PER_CPU; +} + +/* + * Setup the PC, SP, and GP of a secondary processor and start it + * running! + * smp_bootstrap is the place to resume from + * __KSTK_TOS(idle) is apparently the stack pointer + * (unsigned long)idle->thread_info the gp + * assumes a 1:1 mapping of TC => VPE + */ +void prom_boot_secondary(int cpu, struct task_struct *idle) +{ + dvpe(); + set_c0_mvpcontrol(MVPCONTROL_VPC); + + settc(cpu); + + /* restart */ + write_tc_c0_tcrestart((unsigned long)&smp_bootstrap); + + /* enable the tc this vpe/cpu will be running */ + write_tc_c0_tcstatus((read_tc_c0_tcstatus() & ~TCSTATUS_IXMT) | TCSTATUS_A); + + write_tc_c0_tchalt(0); + + /* enable the VPE */ + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); + + /* stack pointer */ + write_tc_gpr_sp( __KSTK_TOS(idle)); + + /* global pointer */ + write_tc_gpr_gp((unsigned long)idle->thread_info); + + flush_icache_range((unsigned long)idle->thread_info, + (unsigned long)idle->thread_info + + sizeof(struct thread_info)); + + /* finally out of configuration and into chaos */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); + + evpe(EVPE_ENABLE); +} + +void prom_init_secondary(void) +{ + write_c0_status((read_c0_status() & ~ST0_IM ) | + (STATUSF_IP0 | STATUSF_IP1 | STATUSF_IP7)); +} + +void prom_smp_finish(void) +{ + write_c0_compare(read_c0_count() + (8* mips_hpt_frequency/HZ)); + + local_irq_enable(); +} + +void prom_cpus_done(void) +{ +} + +void core_send_ipi(int cpu, unsigned int action) +{ + int i; + unsigned long flags; + int vpflags; + + local_irq_save (flags); + + vpflags = dvpe(); /* cant access the other CPU's registers whilst MVPE enabled */ + + switch (action) { + case SMP_CALL_FUNCTION: + i = C_SW1; + break; + + case SMP_RESCHEDULE_YOURSELF: + default: + i = C_SW0; + break; + } + + /* 1:1 mapping of vpe and tc... */ + settc(cpu); + write_vpe_c0_cause(read_vpe_c0_cause() | i); + evpe(vpflags); + + local_irq_restore(flags); +} diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 876aff71cd2..e38f24b2b3d 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -56,6 +58,7 @@ extern asmlinkage void handle_tr(void); extern asmlinkage void handle_fpe(void); extern asmlinkage void handle_mdmx(void); extern asmlinkage void handle_watch(void); +extern asmlinkage void handle_mt(void); extern asmlinkage void handle_dsp(void); extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); @@ -797,6 +800,14 @@ asmlinkage void do_mcheck(struct pt_regs *regs) (regs->cp0_status & ST0_TS) ? "" : "not "); } +asmlinkage void do_mt(struct pt_regs *regs) +{ + die_if_kernel("MIPS MT Thread exception in kernel", regs); + + force_sig(SIGILL, current); +} + + asmlinkage void do_dsp(struct pt_regs *regs) { if (cpu_has_dsp) @@ -1338,6 +1349,9 @@ void __init trap_init(void) if (cpu_has_mcheck) set_except_vector(24, handle_mcheck); + if (cpu_has_mipsmt) + set_except_vector(25, handle_mt); + if (cpu_has_dsp) set_except_vector(26, handle_dsp); diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 6bf42ba08f0..97fefcc9dbe 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -32,7 +32,7 @@ * mknod /dev/vpe0 c 63 0 * mknod /dev/vpe1 c 63 1 */ - +#include #include #include #include @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -697,7 +698,7 @@ int vpe_run(vpe_t * v) dvpe(); /* Put MVPE's into 'configuration state' */ - write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); + set_c0_mvpcontrol(MVPCONTROL_VPC); if (!list_empty(&v->tc)) { if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { @@ -760,7 +761,7 @@ int vpe_run(vpe_t * v) write_vpe_c0_cause(0); /* take system out of configuration state */ - write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); + clear_c0_mvpcontrol(MVPCONTROL_VPC); /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */ write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE | ST0_EXL)); @@ -1134,7 +1135,7 @@ int vpe_free(vpe_handle vpe) evpe_flags = dvpe(); /* Put MVPE's into 'configuration state' */ - write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); + set_c0_mvpcontrol(MVPCONTROL_VPC); settc(t->index); write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); @@ -1145,7 +1146,7 @@ int vpe_free(vpe_handle vpe) v->state = VPE_STATE_UNUSED; - write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); + clear_c0_mvpcontrol(MVPCONTROL_VPC); evpe(evpe_flags); return 0; @@ -1191,7 +1192,7 @@ static int __init vpe_module_init(void) dvpe(); /* Put MVPE's into 'configuration state' */ - write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC); + set_c0_mvpcontrol(MVPCONTROL_VPC); /* dump_mtregs(); */ @@ -1270,7 +1271,7 @@ static int __init vpe_module_init(void) } /* release config state */ - write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC); + clear_c0_mvpcontrol(MVPCONTROL_VPC); return 0; } -- cgit v1.2.3 From 5bcb9a58e6e3eda4af87193c8746d15e45f51628 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 1 Sep 2005 20:42:46 +0000 Subject: Move genrtc.c's functions into Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 2 -- arch/mips/kernel/genrtc.c | 64 ----------------------------------------------- 2 files changed, 66 deletions(-) delete mode 100644 arch/mips/kernel/genrtc.c (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 4c09e1acafd..0213b349617 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -59,8 +59,6 @@ obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_64BIT) += cpu-bugs64.o -obj-$(CONFIG_GEN_RTC) += genrtc.o - CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) CFLAGS_ioctl32.o += -Ifs/ diff --git a/arch/mips/kernel/genrtc.c b/arch/mips/kernel/genrtc.c deleted file mode 100644 index 71416e7bbba..00000000000 --- a/arch/mips/kernel/genrtc.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * A glue layer that provides RTC read/write to drivers/char/genrtc.c driver - * based on MIPS internal RTC routines. It does take care locking - * issues so that we are SMP/Preemption safe. - * - * Copyright (C) 2004 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * Please read the COPYING file for all license details. - */ - -#include - -#include -#include - -static DEFINE_SPINLOCK(mips_rtc_lock); - -unsigned int get_rtc_time(struct rtc_time *time) -{ - unsigned long nowtime; - - spin_lock(&mips_rtc_lock); - nowtime = rtc_get_time(); - to_tm(nowtime, time); - time->tm_year -= 1900; - spin_unlock(&mips_rtc_lock); - - return RTC_24H; -} - -int set_rtc_time(struct rtc_time *time) -{ - unsigned long nowtime; - int ret; - - spin_lock(&mips_rtc_lock); - nowtime = mktime(time->tm_year+1900, time->tm_mon+1, - time->tm_mday, time->tm_hour, time->tm_min, - time->tm_sec); - ret = rtc_set_time(nowtime); - spin_unlock(&mips_rtc_lock); - - return ret; -} - -unsigned int get_rtc_ss(void) -{ - struct rtc_time h; - - get_rtc_time(&h); - return h.tm_sec; -} - -int get_rtc_pll(struct rtc_pll_info *pll) -{ - return -EINVAL; -} - -int set_rtc_pll(struct rtc_pll_info *pll) -{ - return -EINVAL; -} - -- cgit v1.2.3 From 0bf0e3e279661c42ad43014d62ddd87d42da12e7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 15 Sep 2005 16:43:50 +0000 Subject: Fix excessive signal latencies. Signed-off-by: Ralf Baechle --- arch/mips/kernel/entry.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index 6e01b0dd031..83c87fe4ee4 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -105,7 +105,7 @@ work_notifysig: # deal with pending signals and move a0, sp li a1, 0 jal do_notify_resume # a2 already loaded - j restore_all + j resume_userspace FEXPORT(syscall_exit_work_partial) SAVE_STATIC -- cgit v1.2.3 From ea3d710fe572f0af4d242701973f7363b2146429 Mon Sep 17 00:00:00 2001 From: Daniel Jacobowitz Date: Wed, 28 Sep 2005 18:11:15 -0400 Subject: Revise MIPS 64-bit ptrace interface Change the N32 debugging ABI to something more sane, and add support for o32 and n32 debuggers to trace n64 programs. Signed-off-by: Daniel Jacobowitz Signed-off-by: Ralf Baechle --- arch/mips/kernel/ptrace.c | 129 +++++++++++++++++++++++++++++++++++++++++ arch/mips/kernel/ptrace32.c | 81 ++++++++++++++++++++++++++ arch/mips/kernel/scall64-n32.S | 2 +- 3 files changed, 211 insertions(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 74283369a1e..122433f835e 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -38,6 +38,7 @@ #include #include #include +#include /* * Called by kernel/ptrace.c when detaching.. @@ -49,6 +50,118 @@ void ptrace_disable(struct task_struct *child) /* Nothing to do.. */ } +/* + * Read a general register set. We always use the 64-bit format, even + * for 32-bit kernels and for 32-bit processes on a 64-bit kernel. + * Registers are sign extended to fill the available space. + */ +int ptrace_getregs (struct task_struct *child, __s64 __user *data) +{ + struct pt_regs *regs; + int i; + + if (!access_ok(VERIFY_WRITE, data, 38 * 8)) + return -EIO; + + regs = (struct pt_regs *) ((unsigned long) child->thread_info + + THREAD_SIZE - 32 - sizeof(struct pt_regs)); + + for (i = 0; i < 32; i++) + __put_user (regs->regs[i], data + i); + __put_user (regs->lo, data + EF_LO - EF_R0); + __put_user (regs->hi, data + EF_HI - EF_R0); + __put_user (regs->cp0_epc, data + EF_CP0_EPC - EF_R0); + __put_user (regs->cp0_badvaddr, data + EF_CP0_BADVADDR - EF_R0); + __put_user (regs->cp0_status, data + EF_CP0_STATUS - EF_R0); + __put_user (regs->cp0_cause, data + EF_CP0_CAUSE - EF_R0); + + return 0; +} + +/* + * Write a general register set. As for PTRACE_GETREGS, we always use + * the 64-bit format. On a 32-bit kernel only the lower order half + * (according to endianness) will be used. + */ +int ptrace_setregs (struct task_struct *child, __s64 __user *data) +{ + struct pt_regs *regs; + int i; + + if (!access_ok(VERIFY_READ, data, 38 * 8)) + return -EIO; + + regs = (struct pt_regs *) ((unsigned long) child->thread_info + + THREAD_SIZE - 32 - sizeof(struct pt_regs)); + + for (i = 0; i < 32; i++) + __get_user (regs->regs[i], data + i); + __get_user (regs->lo, data + EF_LO - EF_R0); + __get_user (regs->hi, data + EF_HI - EF_R0); + __get_user (regs->cp0_epc, data + EF_CP0_EPC - EF_R0); + + /* badvaddr, status, and cause may not be written. */ + + return 0; +} + +int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) +{ + int i; + + if (!access_ok(VERIFY_WRITE, data, 33 * 8)) + return -EIO; + + if (tsk_used_math(child)) { + fpureg_t *fregs = get_fpu_regs(child); + for (i = 0; i < 32; i++) + __put_user (fregs[i], i + (__u64 __user *) data); + } else { + for (i = 0; i < 32; i++) + __put_user ((__u64) -1, i + (__u64 __user *) data); + } + + if (cpu_has_fpu) { + unsigned int flags, tmp; + + __put_user (child->thread.fpu.hard.fcr31, data + 64); + + flags = read_c0_status(); + __enable_fpu(); + __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); + write_c0_status(flags); + __put_user (tmp, data + 65); + } else { + __put_user (child->thread.fpu.soft.fcr31, data + 64); + __put_user ((__u32) 0, data + 65); + } + + return 0; +} + +int ptrace_setfpregs (struct task_struct *child, __u32 __user *data) +{ + fpureg_t *fregs; + int i; + + if (!access_ok(VERIFY_READ, data, 33 * 8)) + return -EIO; + + fregs = get_fpu_regs(child); + + for (i = 0; i < 32; i++) + __get_user (fregs[i], i + (__u64 __user *) data); + + if (cpu_has_fpu) + __get_user (child->thread.fpu.hard.fcr31, data + 64); + else + __get_user (child->thread.fpu.soft.fcr31, data + 64); + + /* FIR may not be written. */ + + return 0; +} + asmlinkage int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -300,6 +413,22 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) break; } + case PTRACE_GETREGS: + ret = ptrace_getregs (child, (__u64 __user *) data); + break; + + case PTRACE_SETREGS: + ret = ptrace_setregs (child, (__u64 __user *) data); + break; + + case PTRACE_GETFPREGS: + ret = ptrace_getfpregs (child, (__u32 __user *) data); + break; + + case PTRACE_SETFPREGS: + ret = ptrace_setfpregs (child, (__u32 __user *) data); + break; + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 5c45a588022..c28cdddd4c2 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -35,6 +35,12 @@ #include #include +int ptrace_getregs (struct task_struct *child, __s64 __user *data); +int ptrace_setregs (struct task_struct *child, __s64 __user *data); + +int ptrace_getfpregs (struct task_struct *child, __u32 __user *data); +int ptrace_setfpregs (struct task_struct *child, __u32 __user *data); + /* * Tracing a 32-bit process with a 64-bit strace and vice versa will not * work. I don't know how to fix this. @@ -99,6 +105,35 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) break; } + /* + * Read 4 bytes of the other process' storage + * data is a pointer specifying where the user wants the + * 4 bytes copied into + * addr is a pointer in the user's storage that contains an 8 byte + * address in the other process of the 4 bytes that is to be read + * (this is run in a 32-bit process looking at a 64-bit process) + * when I and D space are separate, these will need to be fixed. + */ + case PTRACE_PEEKTEXT_3264: + case PTRACE_PEEKDATA_3264: { + u32 tmp; + int copied; + u32 __user * addrOthers; + + ret = -EIO; + + /* Get the addr in the other process that we want to read */ + if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) + break; + + copied = access_process_vm(child, (u64)addrOthers, &tmp, + sizeof(tmp), 0); + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp, (u32 __user *) (unsigned long) data); + break; + } + /* Read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { struct pt_regs *regs; @@ -202,6 +237,31 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) ret = -EIO; break; + /* + * Write 4 bytes into the other process' storage + * data is the 4 bytes that the user wants written + * addr is a pointer in the user's storage that contains an + * 8 byte address in the other process where the 4 bytes + * that is to be written + * (this is run in a 32-bit process looking at a 64-bit process) + * when I and D space are separate, these will need to be fixed. + */ + case PTRACE_POKETEXT_3264: + case PTRACE_POKEDATA_3264: { + u32 __user * addrOthers; + + /* Get the addr in the other process that we want to write into */ + ret = -EIO; + if (get_user(addrOthers, (u32 __user * __user *) (unsigned long) addr) != 0) + break; + ret = 0; + if (access_process_vm(child, (u64)addrOthers, &data, + sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; + } + case PTRACE_POKEUSR: { struct pt_regs *regs; ret = 0; @@ -276,6 +336,22 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) break; } + case PTRACE_GETREGS: + ret = ptrace_getregs (child, (__u64 __user *) (__u64) data); + break; + + case PTRACE_SETREGS: + ret = ptrace_setregs (child, (__u64 __user *) (__u64) data); + break; + + case PTRACE_GETFPREGS: + ret = ptrace_getfpregs (child, (__u32 __user *) (__u64) data); + break; + + case PTRACE_SETFPREGS: + ret = ptrace_setfpregs (child, (__u32 __user *) (__u64) data); + break; + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: { /* restart after signal. */ ret = -EIO; @@ -320,6 +396,11 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) (unsigned int __user *) (unsigned long) data); break; + case PTRACE_GET_THREAD_AREA_3264: + ret = put_user(child->thread_info->tp_value, + (unsigned long __user *) (unsigned long) data); + break; + default: ret = ptrace_request(child, request, addr, data); break; diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index b32c566e0a2..7e66eb823bf 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -216,7 +216,7 @@ EXPORT(sysn32_call_table) PTR compat_sys_getrusage PTR sys32_sysinfo PTR compat_sys_times - PTR sys_ptrace + PTR sys32_ptrace PTR sys_getuid /* 6100 */ PTR sys_syslog PTR sys_getgid -- cgit v1.2.3 From b288f135872b651ebf6cd1565d0709a5e31997f7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 30 Sep 2005 01:51:21 +0100 Subject: Switch Sibyte profiling driver to ->compat_ioctl Signed-off-by: Christoph Hellwig Signed-off-by: Ralf Baechle --- arch/mips/kernel/ioctl32.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ioctl32.c b/arch/mips/kernel/ioctl32.c index c069719ff0d..ed9b2da510b 100644 --- a/arch/mips/kernel/ioctl32.c +++ b/arch/mips/kernel/ioctl32.c @@ -41,12 +41,6 @@ IOCTL_TABLE_START #define DECLARES #include "compat_ioctl.c" -#ifdef CONFIG_SIBYTE_TBPROF -COMPATIBLE_IOCTL(SBPROF_ZBSTART) -COMPATIBLE_IOCTL(SBPROF_ZBSTOP) -COMPATIBLE_IOCTL(SBPROF_ZBWAITFULL) -#endif /* CONFIG_SIBYTE_TBPROF */ - /*HANDLE_IOCTL(RTC_IRQP_READ, w_long) COMPATIBLE_IOCTL(RTC_IRQP_SET) HANDLE_IOCTL(RTC_EPOCH_READ, w_long) -- cgit v1.2.3 From c78cbf49c4edf2f9ca9e56d4b87a5d6ef08b7fed Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 30 Sep 2005 13:59:37 +0100 Subject: Support for MIPSsim, the cycle accurate MIPS simulator. Signed-off-by: Ralf Baechle --- arch/mips/kernel/head.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index d2de5d025db..2e9122a4213 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -116,7 +116,7 @@ EXPORT(stext) # used for profiling EXPORT(_stext) -#ifdef CONFIG_QEMU +#if defined(CONFIG_QEMU) || defined(CONFIG_MIPS_SIM) /* * Give us a fighting chance of running if execution beings at the * kernel load address. This is needed because this platform does -- cgit v1.2.3 From 02cf2119684e52e97a8a90bd7630386e0f1a250a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 1 Oct 2005 13:06:32 +0100 Subject: Cleanup the mess in cpu_cache_init. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 5d71eca4157..8e6427a5091 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -191,7 +191,7 @@ static inline int __cpu_has_fpu(void) return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE); } -#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \ +#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \ | MIPS_CPU_COUNTER) static inline void cpu_probe_legacy(struct cpuinfo_mips *c) @@ -200,7 +200,8 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c) case PRID_IMP_R2000: c->cputype = CPU_R2000; c->isa_level = MIPS_CPU_ISA_I; - c->options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX; + c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | + MIPS_CPU_NOFPUEX; if (__cpu_has_fpu()) c->options |= MIPS_CPU_FPU; c->tlbsize = 64; @@ -214,7 +215,8 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c) else c->cputype = CPU_R3000; c->isa_level = MIPS_CPU_ISA_I; - c->options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX; + c->options = MIPS_CPU_TLB | MIPS_CPU_3K_CACHE | + MIPS_CPU_NOFPUEX; if (__cpu_has_fpu()) c->options |= MIPS_CPU_FPU; c->tlbsize = 64; @@ -297,7 +299,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c) #endif case PRID_IMP_TX39: c->isa_level = MIPS_CPU_ISA_I; - c->options = MIPS_CPU_TLB; + c->options = MIPS_CPU_TLB | MIPS_CPU_TX39_CACHE; if ((c->processor_id & 0xf0) == (PRID_REV_TX3927 & 0xf0)) { c->cputype = CPU_TX3927; @@ -441,7 +443,7 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c) config0 = read_c0_config(); if (((config0 & MIPS_CONF_MT) >> 7) == 1) - c->options |= MIPS_CPU_TLB | MIPS_CPU_4KTLB; + c->options |= MIPS_CPU_TLB; isa = (config0 & MIPS_CONF_AT) >> 13; switch (isa) { case 0: @@ -516,8 +518,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) static inline void decode_configs(struct cpuinfo_mips *c) { /* MIPS32 or MIPS64 compliant CPU. */ - c->options = MIPS_CPU_4KEX | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC | - MIPS_CPU_LLSC | MIPS_CPU_MCHECK; + c->options = MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER | + MIPS_CPU_DIVEC | MIPS_CPU_LLSC | MIPS_CPU_MCHECK; c->scache.flags = MIPS_CACHE_NOT_PRESENT; @@ -603,6 +605,15 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c) static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) { decode_configs(c); + + /* + * For historical reasons the SB1 comes with it's own variant of + * cache code which eventually will be folded into c-r4k.c. Until + * then we pretend it's got it's own cache architecture. + */ + c->options &= MIPS_CPU_4K_CACHE; + c->options |= MIPS_CPU_SB1_CACHE; + switch (c->processor_id & 0xff00) { case PRID_IMP_SB1: c->cputype = CPU_SB1; -- cgit v1.2.3 From f8bb3af924211b0e6ee66dc0d3bcb4a66ba59af4 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 3 Oct 2005 13:30:57 +0100 Subject: Make kgdb_wait static. Nothing outside gdb-stub.c uses kgdb_wait, so change it's definition to static. Signed-off-by: Ralf Baechle --- arch/mips/kernel/gdb-stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index ba0afb4a649..3af94207f2b 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -654,7 +654,7 @@ void set_async_breakpoint(unsigned long *epc) *epc = (unsigned long)async_breakpoint; } -void kgdb_wait(void *arg) +static void kgdb_wait(void *arg) { unsigned flags; int cpu = smp_processor_id(); -- cgit v1.2.3 From 57468af3267bfb89391f9c607a9637e86e55d299 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 3 Oct 2005 13:40:26 +0100 Subject: Define and initialize kdb_lock using DEFINE_SPINLOCK. Convert kgdb_cpulock into a raw_spinlock_t. SPIN_LOCK_UNLOCKED is deprecated and it's replacement DEFINE_SPINLOCK is not suitable for arrays of spinlocks. Signed-off-by: Ralf Baechle --- arch/mips/kernel/gdb-stub.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/gdb-stub.c b/arch/mips/kernel/gdb-stub.c index 3af94207f2b..96d18c43dca 100644 --- a/arch/mips/kernel/gdb-stub.c +++ b/arch/mips/kernel/gdb-stub.c @@ -176,8 +176,10 @@ int kgdb_enabled; /* * spin locks for smp case */ -static spinlock_t kgdb_lock = SPIN_LOCK_UNLOCKED; -static spinlock_t kgdb_cpulock[NR_CPUS] = { [0 ... NR_CPUS-1] = SPIN_LOCK_UNLOCKED}; +static DEFINE_SPINLOCK(kgdb_lock); +static raw_spinlock_t kgdb_cpulock[NR_CPUS] = { + [0 ... NR_CPUS-1] = __RAW_SPIN_LOCK_UNLOCKED; +}; /* * BUFMAX defines the maximum number of characters in inbound/outbound buffers @@ -661,8 +663,8 @@ static void kgdb_wait(void *arg) local_irq_save(flags); - spin_lock(&kgdb_cpulock[cpu]); - spin_unlock(&kgdb_cpulock[cpu]); + __raw_spin_lock(&kgdb_cpulock[cpu]); + __raw_spin_unlock(&kgdb_cpulock[cpu]); local_irq_restore(flags); } @@ -710,7 +712,7 @@ void handle_exception (struct gdb_regs *regs) * acquire the CPU spinlocks */ for (i = num_online_cpus()-1; i >= 0; i--) - if (spin_trylock(&kgdb_cpulock[i]) == 0) + if (__raw_spin_trylock(&kgdb_cpulock[i]) == 0) panic("kgdb: couldn't get cpulock %d\n", i); /* @@ -985,7 +987,7 @@ finish_kgdb: exit_kgdb_exception: /* release locks so other CPUs can go */ for (i = num_online_cpus()-1; i >= 0; i--) - spin_unlock(&kgdb_cpulock[i]); + __raw_spin_unlock(&kgdb_cpulock[i]); spin_unlock(&kgdb_lock); __flush_cache_all(); -- cgit v1.2.3 From 8afcb5d82934c83fb01664ae00eaff9de1d8d340 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 4 Oct 2005 15:01:26 +0100 Subject: Detect 4KSD and treat it like 4KSc. Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 8e6427a5091..72c580d94e2 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -548,6 +548,7 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c) c->cputype = CPU_4KEC; break; case PRID_IMP_4KSC: + case PRID_IMP_4KSD: c->cputype = CPU_4KSC; break; case PRID_IMP_5KC: -- cgit v1.2.3 From 101b3531a693ad890f33f2f04323592cd376616a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 6 Oct 2005 17:39:32 +0100 Subject: Protect manipulation of c0_status against preemption and multithreading. Signed-off-by: Ralf Baechle --- arch/mips/kernel/ptrace.c | 39 +++++++++++++++++++++++++++++++-------- arch/mips/kernel/ptrace32.c | 20 ++++++++++++++++---- 2 files changed, 47 insertions(+), 12 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 122433f835e..fcceab8f2e0 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -126,10 +127,21 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) __put_user (child->thread.fpu.hard.fcr31, data + 64); - flags = read_c0_status(); - __enable_fpu(); - __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); - write_c0_status(flags); + preempt_disable(); + if (cpu_has_mipsmt) { + unsigned int vpflags = dvpe(); + flags = read_c0_status(); + __enable_fpu(); + __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); + write_c0_status(flags); + evpe(vpflags); + } else { + flags = read_c0_status(); + __enable_fpu(); + __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); + write_c0_status(flags); + } + preempt_enable(); __put_user (tmp, data + 65); } else { __put_user (child->thread.fpu.soft.fcr31, data + 64); @@ -284,10 +296,21 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if (!cpu_has_fpu) break; - flags = read_c0_status(); - __enable_fpu(); - __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); - write_c0_status(flags); + preempt_disable(); + if (cpu_has_mipsmt) { + unsigned int vpflags = dvpe(); + flags = read_c0_status(); + __enable_fpu(); + __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); + write_c0_status(flags); + evpe(vpflags); + } else { + flags = read_c0_status(); + __enable_fpu(); + __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); + write_c0_status(flags); + } + preempt_enable(); break; } case DSP_BASE ... DSP_BASE + 5: { diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index c28cdddd4c2..9a9b0497213 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -191,10 +192,21 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) if (!cpu_has_fpu) break; - flags = read_c0_status(); - __enable_fpu(); - __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); - write_c0_status(flags); + preempt_disable(); + if (cpu_has_mipsmt) { + unsigned int vpflags = dvpe(); + flags = read_c0_status(); + __enable_fpu(); + __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); + write_c0_status(flags); + evpe(vpflags); + } else { + flags = read_c0_status(); + __enable_fpu(); + __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); + write_c0_status(flags); + } + preempt_enable(); break; } case DSP_BASE ... DSP_BASE + 5: -- cgit v1.2.3 From ec917c2c1ab4359a1d438e62daeb50cc42e632e1 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 7 Oct 2005 16:58:15 +0100 Subject: Fixup a few lose ends in explicit support for MIPS R1/R2. Signed-off-by: Ralf Baechle --- arch/mips/kernel/Makefile | 4 ++-- arch/mips/kernel/r4k_switch.S | 2 +- arch/mips/kernel/traps.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 0213b349617..72f2126ad19 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -28,8 +28,8 @@ obj-$(CONFIG_CPU_RM9000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_NEVADA) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R10000) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_SB1) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_MIPS32_R1) += r4k_fpu.o r4k_switch.o -obj-$(CONFIG_CPU_MIPS64_R1) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o +obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o obj-$(CONFIG_CPU_R6000) += r6000_fpu.o r4k_switch.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 27361f44def..d2afbd19a9c 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -165,7 +165,7 @@ LEAF(_init_fpu) 1: #endif -#ifdef CONFIG_CPU_MIPS32_R1 +#ifdef CONFIG_CPU_MIPS32 mtc1 t1, $f0 mtc1 t1, $f1 mtc1 t1, $f2 diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index e38f24b2b3d..eccae819160 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -885,7 +885,7 @@ asmlinkage void cache_parity_error(void) reg_val & (1<<22) ? "E0 " : ""); printk("IDX: 0x%08x\n", reg_val & ((1<<22)-1)); -#if defined(CONFIG_CPU_MIPS32_R1) || defined(CONFIG_CPU_MIPS64_R1) +#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) if (reg_val & (1<<22)) printk("DErrAddr0: 0x%0*lx\n", field, read_c0_derraddr0()); -- cgit v1.2.3 From 9383292f179e1907e7e7ade539ac8fd3b65c1e97 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 14 Jan 2005 03:03:23 +0000 Subject: Date: Fri Jan 14 03:03:23 2005 +0000 Locking cleanups. Signed-off-by: Ralf Baechle --- arch/mips/kernel/i8259.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 911537413b6..b974ac9057f 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -31,7 +31,7 @@ void disable_8259A_irq(unsigned int irq); * moves to arch independent land */ -spinlock_t DEFINE_SPINLOCK(i8259A_lock); +DEFINE_SPINLOCK(i8259A_lock); static void end_8259A_irq (unsigned int irq) { -- cgit v1.2.3 From 178086c86ac9738a76f1462e9ee4cbe8fd3b8c51 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 13 Oct 2005 17:07:54 +0100 Subject: Don't print file name and line in die and die_if_kernel. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index eccae819160..a3c00512696 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -276,30 +276,18 @@ void show_registers(struct pt_regs *regs) static DEFINE_SPINLOCK(die_lock); -NORET_TYPE void ATTRIB_NORET __die(const char * str, struct pt_regs * regs, - const char * file, const char * func, - unsigned long line) +NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs) { static int die_counter; console_verbose(); spin_lock_irq(&die_lock); - printk("%s", str); - if (file && func) - printk(" in %s:%s, line %ld", file, func, line); - printk("[#%d]:\n", ++die_counter); + printk("%s[#%d]:\n", str, ++die_counter); show_registers(regs); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } -void __die_if_kernel(const char * str, struct pt_regs * regs, - const char * file, const char * func, unsigned long line) -{ - if (!user_mode(regs)) - __die(str, regs, file, func, line); -} - extern const struct exception_table_entry __start___dbe_table[]; extern const struct exception_table_entry __stop___dbe_table[]; -- cgit v1.2.3 From 12616ed202ba66af6e1386df02d06c72d7386339 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 18 Oct 2005 10:26:46 +0100 Subject: FPU emulator garbage collection. First argument of fpu_emulator_cop1Handler() was unused. Signed-off-by: Ralf Baechle --- arch/mips/kernel/traps.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index a3c00512696..6f3ff969068 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -63,7 +63,7 @@ extern asmlinkage void handle_dsp(void); extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); -extern int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp, +extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx); void (*board_be_init)(void); @@ -589,7 +589,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) preempt_enable(); /* Run the emulator */ - sig = fpu_emulator_cop1Handler (0, regs, + sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu.soft); preempt_disable(); @@ -743,7 +743,7 @@ asmlinkage void do_cpu(struct pt_regs *regs) preempt_enable(); if (!cpu_has_fpu) { - int sig = fpu_emulator_cop1Handler(0, regs, + int sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu.soft); if (sig) force_sig(sig, current); -- cgit v1.2.3 From 0d507d61cd1cce6d920e78fe10e67296abb2a1eb Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 18 Oct 2005 12:48:31 +0100 Subject: Sys_lookup_dcookie arguments occupy 4 argument slots. Signed-off-by: Ralf Baechle --- arch/mips/kernel/scall32-o32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index fd1823c1657..4dd8e8b4fbc 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -587,7 +587,7 @@ einval: li v0, -EINVAL sys sys_io_submit 3 sys sys_io_cancel 3 /* 4245 */ sys sys_exit_group 1 - sys sys_lookup_dcookie 3 + sys sys_lookup_dcookie 4 sys sys_epoll_create 1 sys sys_epoll_ctl 4 sys sys_epoll_wait 3 /* 4250 */ -- cgit v1.2.3 From f4c72cc737561aab0d9c7f877abbc0a853f1c465 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 18 Oct 2005 13:25:29 +0100 Subject: Get 64-bit right in the kgdb stub. Signed-off-by: Ralf Baechle --- arch/mips/kernel/gdb-low.S | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/gdb-low.S b/arch/mips/kernel/gdb-low.S index 512bedbfa7b..83b8986f940 100644 --- a/arch/mips/kernel/gdb-low.S +++ b/arch/mips/kernel/gdb-low.S @@ -52,16 +52,15 @@ /* * Called from user mode, go somewhere else. */ - lui k1, %hi(saved_vectors) mfc0 k0, CP0_CAUSE andi k0, k0, 0x7c add k1, k1, k0 - lw k0, %lo(saved_vectors)(k1) + PTR_L k0, saved_vectors(k1) jr k0 nop 1: move k0, sp - subu sp, k1, GDB_FR_SIZE*2 # see comment above + PTR_SUBU sp, k1, GDB_FR_SIZE*2 # see comment above LONG_S k0, GDB_FR_REG29(sp) LONG_S $2, GDB_FR_REG2(sp) -- cgit v1.2.3 From d121ced21d79eab7726bfe6b1e33da4ae86072c0 Mon Sep 17 00:00:00 2001 From: Andrew Isaacson Date: Wed, 19 Oct 2005 23:54:43 -0700 Subject: Sibyte fixes Fix typo in cpu_probe_sibyte. Signed-Off-By: Andy Isaacson Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 72c580d94e2..f7a841573b8 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -612,7 +612,7 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) * cache code which eventually will be folded into c-r4k.c. Until * then we pretend it's got it's own cache architecture. */ - c->options &= MIPS_CPU_4K_CACHE; + c->options &= ~MIPS_CPU_4K_CACHE; c->options |= MIPS_CPU_SB1_CACHE; switch (c->processor_id & 0xff00) { -- cgit v1.2.3 From 93ce2f524e96571711029884e6340c790a029b94 Mon Sep 17 00:00:00 2001 From: Andrew Isaacson Date: Wed, 19 Oct 2005 23:56:20 -0700 Subject: Add support for SB1A CPU. Signed-Off-By: Andy Isaacson Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 3 +++ arch/mips/kernel/proc.c | 1 + 2 files changed, 4 insertions(+) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index f7a841573b8..a263fb7a397 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -623,6 +623,9 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c) c->options &= ~(MIPS_CPU_FPU | MIPS_CPU_32FPR); #endif break; + case PRID_IMP_SB1A: + c->cputype = CPU_SB1A; + break; } } diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index f2b0446e44b..86fe15b273c 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -56,6 +56,7 @@ static const char *cpu_name[] = { [CPU_5KC] = "MIPS 5Kc", [CPU_R4310] = "R4310", [CPU_SB1] = "SiByte SB1", + [CPU_SB1A] = "SiByte SB1A", [CPU_TX3912] = "TX3912", [CPU_TX3922] = "TX3922", [CPU_TX3927] = "TX3927", -- cgit v1.2.3 From 030274ae03c20f9ac27d4218118b9679d7c680d8 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 21 Oct 2005 22:26:07 +0100 Subject: Remove useless casts of kmalloc return values. Signed-off-by: Ralf Baechle --- arch/mips/kernel/irixelf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/mips/kernel') diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c index 5aeacc1ffb2..99262fe6456 100644 --- a/arch/mips/kernel/irixelf.c +++ b/arch/mips/kernel/irixelf.c @@ -422,9 +422,7 @@ static inline int look_for_irix_interpreter(char **name, if (*name != NULL) goto out; - *name = (char *) kmalloc((epp->p_filesz + - strlen(IRIX_EMUL)), - GFP_KERNEL); + *name = kmalloc(epp->p_filesz + strlen(IRIX_EMUL), GFP_KERNEL); if (!*name) return -ENOMEM; -- cgit v1.2.3