diff options
Diffstat (limited to 'arch/m68k/kernel')
-rw-r--r-- | arch/m68k/kernel/Makefile | 23 | ||||
-rw-r--r-- | arch/m68k/kernel/Makefile_mm | 17 | ||||
-rw-r--r-- | arch/m68k/kernel/Makefile_no | 10 | ||||
-rw-r--r-- | arch/m68k/kernel/dma_mm.c | 1 | ||||
-rw-r--r-- | arch/m68k/kernel/dma_no.c | 1 | ||||
-rw-r--r-- | arch/m68k/kernel/entry_mm.S | 7 | ||||
-rw-r--r-- | arch/m68k/kernel/entry_no.S | 6 | ||||
-rw-r--r-- | arch/m68k/kernel/ints.c | 323 | ||||
-rw-r--r-- | arch/m68k/kernel/irq.c | 10 | ||||
-rw-r--r-- | arch/m68k/kernel/module.c | 130 | ||||
-rw-r--r-- | arch/m68k/kernel/module_mm.c | 155 | ||||
-rw-r--r-- | arch/m68k/kernel/module_no.c | 126 | ||||
-rw-r--r-- | arch/m68k/kernel/process_mm.c | 2 | ||||
-rw-r--r-- | arch/m68k/kernel/process_no.c | 2 | ||||
-rw-r--r-- | arch/m68k/kernel/setup_mm.c | 2 | ||||
-rw-r--r-- | arch/m68k/kernel/setup_no.c | 4 | ||||
-rw-r--r-- | arch/m68k/kernel/syscalltable.S | 2 | ||||
-rw-r--r-- | arch/m68k/kernel/traps.c | 1108 | ||||
-rw-r--r-- | arch/m68k/kernel/traps_mm.c | 1207 | ||||
-rw-r--r-- | arch/m68k/kernel/traps_no.c | 365 | ||||
-rw-r--r-- | arch/m68k/kernel/vectors.c | 145 | ||||
-rw-r--r-- | arch/m68k/kernel/vmlinux.lds_no.S | 1 |
22 files changed, 1451 insertions, 2196 deletions
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index c482ebc9dd5..c5696193281 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -1,5 +1,20 @@ -ifdef CONFIG_MMU -include arch/m68k/kernel/Makefile_mm -else -include arch/m68k/kernel/Makefile_no +# +# Makefile for the linux kernel. +# + +extra-$(CONFIG_MMU) := head.o +extra-$(CONFIG_SUN3) := sun3-head.o +extra-y += vmlinux.lds + +obj-y := entry.o irq.o m68k_ksyms.o module.o process.o ptrace.o setup.o \ + signal.o sys_m68k.o syscalltable.o time.o traps.o + +obj-$(CONFIG_MMU) += ints.o vectors.o + +ifndef CONFIG_MMU_SUN3 +obj-y += dma.o endif +ifndef CONFIG_MMU +obj-y += init_task.o +endif + diff --git a/arch/m68k/kernel/Makefile_mm b/arch/m68k/kernel/Makefile_mm deleted file mode 100644 index aced6780457..00000000000 --- a/arch/m68k/kernel/Makefile_mm +++ /dev/null @@ -1,17 +0,0 @@ -# -# Makefile for the linux kernel. -# - -ifndef CONFIG_SUN3 - extra-y := head.o -else - extra-y := sun3-head.o -endif -extra-y += vmlinux.lds - -obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ - sys_m68k.o time.o setup.o m68k_ksyms.o devres.o syscalltable.o - -devres-y = ../../../kernel/irq/devres.o - -obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo diff --git a/arch/m68k/kernel/Makefile_no b/arch/m68k/kernel/Makefile_no deleted file mode 100644 index 37c3fc074c0..00000000000 --- a/arch/m68k/kernel/Makefile_no +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for arch/m68knommu/kernel. -# - -extra-y := vmlinux.lds - -obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \ - setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o - -obj-$(CONFIG_MODULES) += module.o diff --git a/arch/m68k/kernel/dma_mm.c b/arch/m68k/kernel/dma_mm.c index 4bbb3c2a888..a3c471b523f 100644 --- a/arch/m68k/kernel/dma_mm.c +++ b/arch/m68k/kernel/dma_mm.c @@ -12,6 +12,7 @@ #include <linux/scatterlist.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include <linux/export.h> #include <asm/pgalloc.h> diff --git a/arch/m68k/kernel/dma_no.c b/arch/m68k/kernel/dma_no.c index fc61541aeb7..f1dc3fc71bc 100644 --- a/arch/m68k/kernel/dma_no.c +++ b/arch/m68k/kernel/dma_no.c @@ -10,6 +10,7 @@ #include <linux/mm.h> #include <linux/device.h> #include <linux/dma-mapping.h> +#include <linux/export.h> #include <asm/cacheflush.h> void *dma_alloc_coherent(struct device *dev, size_t size, diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S index bd0ec05263b..c713f514843 100644 --- a/arch/m68k/kernel/entry_mm.S +++ b/arch/m68k/kernel/entry_mm.S @@ -48,7 +48,7 @@ .globl sys_fork, sys_clone, sys_vfork .globl ret_from_interrupt, bad_interrupt .globl auto_irqhandler_fixup -.globl user_irqvec_fixup, user_irqhandler_fixup +.globl user_irqvec_fixup .text ENTRY(buserr) @@ -207,7 +207,7 @@ ENTRY(auto_inthandler) movel %sp,%sp@- movel %d0,%sp@- | put vector # on stack auto_irqhandler_fixup = . + 2 - jsr __m68k_handle_int | process the IRQ + jsr do_IRQ | process the IRQ addql #8,%sp | pop parameters off stack ret_from_interrupt: @@ -240,8 +240,7 @@ user_irqvec_fixup = . + 2 movel %sp,%sp@- movel %d0,%sp@- | put vector # on stack -user_irqhandler_fixup = . + 2 - jsr __m68k_handle_int | process the IRQ + jsr do_IRQ | process the IRQ addql #8,%sp | pop parameters off stack subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) diff --git a/arch/m68k/kernel/entry_no.S b/arch/m68k/kernel/entry_no.S index 5f0f6b598b5..1b4289061a6 100644 --- a/arch/m68k/kernel/entry_no.S +++ b/arch/m68k/kernel/entry_no.S @@ -43,7 +43,7 @@ .globl sys_vfork ENTRY(buserr) - SAVE_ALL + SAVE_ALL_INT moveq #-1,%d0 movel %d0,%sp@(PT_OFF_ORIG_D0) movel %sp,%sp@- /* stack frame pointer argument */ @@ -52,7 +52,7 @@ ENTRY(buserr) jra ret_from_exception ENTRY(trap) - SAVE_ALL + SAVE_ALL_INT moveq #-1,%d0 movel %d0,%sp@(PT_OFF_ORIG_D0) movel %sp,%sp@- /* stack frame pointer argument */ @@ -64,7 +64,7 @@ ENTRY(trap) .globl dbginterrupt ENTRY(dbginterrupt) - SAVE_ALL + SAVE_ALL_INT moveq #-1,%d0 movel %d0,%sp@(PT_OFF_ORIG_D0) movel %sp,%sp@- /* stack frame pointer argument */ diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index 761ee0440c9..74fefac0089 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c @@ -4,25 +4,6 @@ * 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. - * - * 07/03/96: Timer initialization, and thus mach_sched_init(), - * removed from request_irq() and moved to init_time(). - * We should therefore consider renaming our add_isr() and - * remove_isr() to request_irq() and free_irq() - * respectively, so they are compliant with the other - * architectures. /Jes - * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls. - * Removed irq list support, if any machine needs an irq server - * it must implement this itself (as it's already done), instead - * only default handler are used with mach_default_handler. - * request_irq got some flags different from other architectures: - * - IRQ_FLG_REPLACE : Replace an existing handler (the default one - * can be replaced without this flag) - * - IRQ_FLG_LOCK : handler can't be replaced - * There are other machine depending flags, see there - * If you want to replace a default handler you should know what - * you're doing, since it might handle different other irq sources - * which must be served /Roman Zippel */ #include <linux/module.h> @@ -47,33 +28,22 @@ #endif extern u32 auto_irqhandler_fixup[]; -extern u32 user_irqhandler_fixup[]; extern u16 user_irqvec_fixup[]; -/* table for system interrupt handlers */ -static struct irq_node *irq_list[NR_IRQS]; -static struct irq_controller *irq_controller[NR_IRQS]; -static int irq_depth[NR_IRQS]; - static int m68k_first_user_vec; -static struct irq_controller auto_irq_controller = { +static struct irq_chip auto_irq_chip = { .name = "auto", - .lock = __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock), - .startup = m68k_irq_startup, - .shutdown = m68k_irq_shutdown, + .irq_startup = m68k_irq_startup, + .irq_shutdown = m68k_irq_shutdown, }; -static struct irq_controller user_irq_controller = { +static struct irq_chip user_irq_chip = { .name = "user", - .lock = __SPIN_LOCK_UNLOCKED(user_irq_controller.lock), - .startup = m68k_irq_startup, - .shutdown = m68k_irq_shutdown, + .irq_startup = m68k_irq_startup, + .irq_shutdown = m68k_irq_shutdown, }; -#define NUM_IRQ_NODES 100 -static irq_node_t nodes[NUM_IRQ_NODES]; - /* * void init_IRQ(void) * @@ -96,7 +66,7 @@ void __init init_IRQ(void) } for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) - irq_controller[i] = &auto_irq_controller; + irq_set_chip_and_handler(i, &auto_irq_chip, handle_simple_irq); mach_init_IRQ(); } @@ -106,7 +76,7 @@ void __init init_IRQ(void) * @handler: called from auto vector interrupts * * setup the handler to be called from auto vector interrupts instead of the - * standard __m68k_handle_int(), it will be called with irq numbers in the range + * standard do_IRQ(), it will be called with irq numbers in the range * from IRQ_AUTO_1 - IRQ_AUTO_7. */ void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) @@ -120,217 +90,49 @@ void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_re * m68k_setup_user_interrupt * @vec: first user vector interrupt to handle * @cnt: number of active user vector interrupts - * @handler: called from user vector interrupts * * setup user vector interrupts, this includes activating the specified range * of interrupts, only then these interrupts can be requested (note: this is - * different from auto vector interrupts). An optional handler can be installed - * to be called instead of the default __m68k_handle_int(), it will be called - * with irq numbers starting from IRQ_USER. + * different from auto vector interrupts). */ -void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, - void (*handler)(unsigned int, struct pt_regs *)) +void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt) { int i; BUG_ON(IRQ_USER + cnt > NR_IRQS); m68k_first_user_vec = vec; for (i = 0; i < cnt; i++) - irq_controller[IRQ_USER + i] = &user_irq_controller; + irq_set_chip(IRQ_USER + i, &user_irq_chip); *user_irqvec_fixup = vec - IRQ_USER; - if (handler) - *user_irqhandler_fixup = (u32)handler; flush_icache(); } /** * m68k_setup_irq_controller - * @contr: irq controller which controls specified irq + * @chip: irq chip which controls specified irq + * @handle: flow handler which handles specified irq * @irq: first irq to be managed by the controller + * @cnt: number of irqs to be managed by the controller * * Change the controller for the specified range of irq, which will be used to * manage these irq. auto/user irq already have a default controller, which can * be changed as well, but the controller probably should use m68k_irq_startup/ * m68k_irq_shutdown. */ -void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq, +void m68k_setup_irq_controller(struct irq_chip *chip, + irq_flow_handler_t handle, unsigned int irq, unsigned int cnt) { int i; - for (i = 0; i < cnt; i++) - irq_controller[irq + i] = contr; -} - -irq_node_t *new_irq_node(void) -{ - irq_node_t *node; - short i; - - for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) { - if (!node->handler) { - memset(node, 0, sizeof(*node)); - return node; - } + for (i = 0; i < cnt; i++) { + irq_set_chip(irq + i, chip); + if (handle) + irq_set_handler(irq + i, handle); } - - printk ("new_irq_node: out of nodes\n"); - return NULL; } -int setup_irq(unsigned int irq, struct irq_node *node) -{ - struct irq_controller *contr; - struct irq_node **prev; - unsigned long flags; - - if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { - printk("%s: Incorrect IRQ %d from %s\n", - __func__, irq, node->devname); - return -ENXIO; - } - - spin_lock_irqsave(&contr->lock, flags); - - prev = irq_list + irq; - if (*prev) { - /* Can't share interrupts unless both agree to */ - if (!((*prev)->flags & node->flags & IRQF_SHARED)) { - spin_unlock_irqrestore(&contr->lock, flags); - return -EBUSY; - } - while (*prev) - prev = &(*prev)->next; - } - - if (!irq_list[irq]) { - if (contr->startup) - contr->startup(irq); - else - contr->enable(irq); - } - node->next = NULL; - *prev = node; - - spin_unlock_irqrestore(&contr->lock, flags); - - return 0; -} - -int request_irq(unsigned int irq, - irq_handler_t handler, - unsigned long flags, const char *devname, void *dev_id) -{ - struct irq_node *node; - int res; - - node = new_irq_node(); - if (!node) - return -ENOMEM; - - node->handler = handler; - node->flags = flags; - node->dev_id = dev_id; - node->devname = devname; - - res = setup_irq(irq, node); - if (res) - node->handler = NULL; - - return res; -} - -EXPORT_SYMBOL(request_irq); - -void free_irq(unsigned int irq, void *dev_id) -{ - struct irq_controller *contr; - struct irq_node **p, *node; - unsigned long flags; - - if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { - printk("%s: Incorrect IRQ %d\n", __func__, irq); - return; - } - - spin_lock_irqsave(&contr->lock, flags); - - p = irq_list + irq; - while ((node = *p)) { - if (node->dev_id == dev_id) - break; - p = &node->next; - } - - if (node) { - *p = node->next; - node->handler = NULL; - } else - printk("%s: Removing probably wrong IRQ %d\n", - __func__, irq); - - if (!irq_list[irq]) { - if (contr->shutdown) - contr->shutdown(irq); - else - contr->disable(irq); - } - - spin_unlock_irqrestore(&contr->lock, flags); -} - -EXPORT_SYMBOL(free_irq); - -void enable_irq(unsigned int irq) -{ - struct irq_controller *contr; - unsigned long flags; - - if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { - printk("%s: Incorrect IRQ %d\n", - __func__, irq); - return; - } - - spin_lock_irqsave(&contr->lock, flags); - if (irq_depth[irq]) { - if (!--irq_depth[irq]) { - if (contr->enable) - contr->enable(irq); - } - } else - WARN_ON(1); - spin_unlock_irqrestore(&contr->lock, flags); -} - -EXPORT_SYMBOL(enable_irq); - -void disable_irq(unsigned int irq) -{ - struct irq_controller *contr; - unsigned long flags; - - if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { - printk("%s: Incorrect IRQ %d\n", - __func__, irq); - return; - } - - spin_lock_irqsave(&contr->lock, flags); - if (!irq_depth[irq]++) { - if (contr->disable) - contr->disable(irq); - } - spin_unlock_irqrestore(&contr->lock, flags); -} - -EXPORT_SYMBOL(disable_irq); - -void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq"))); - -EXPORT_SYMBOL(disable_irq_nosync); - -int m68k_irq_startup(unsigned int irq) +unsigned int m68k_irq_startup_irq(unsigned int irq) { if (irq <= IRQ_AUTO_7) vectors[VEC_SPUR + irq] = auto_inthandler; @@ -339,41 +141,21 @@ int m68k_irq_startup(unsigned int irq) return 0; } -void m68k_irq_shutdown(unsigned int irq) +unsigned int m68k_irq_startup(struct irq_data *data) { - if (irq <= IRQ_AUTO_7) - vectors[VEC_SPUR + irq] = bad_inthandler; - else - vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; + return m68k_irq_startup_irq(data->irq); } - -/* - * Do we need these probe functions on the m68k? - * - * ... may be useful with ISA devices - */ -unsigned long probe_irq_on (void) +void m68k_irq_shutdown(struct irq_data *data) { -#ifdef CONFIG_Q40 - if (MACH_IS_Q40) - return q40_probe_irq_on(); -#endif - return 0; -} + unsigned int irq = data->irq; -EXPORT_SYMBOL(probe_irq_on); - -int probe_irq_off (unsigned long irqs) -{ -#ifdef CONFIG_Q40 - if (MACH_IS_Q40) - return q40_probe_irq_off(irqs); -#endif - return 0; + if (irq <= IRQ_AUTO_7) + vectors[VEC_SPUR + irq] = bad_inthandler; + else + vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; } -EXPORT_SYMBOL(probe_irq_off); unsigned int irq_canonicalize(unsigned int irq) { @@ -386,52 +168,9 @@ unsigned int irq_canonicalize(unsigned int irq) EXPORT_SYMBOL(irq_canonicalize); -asmlinkage void m68k_handle_int(unsigned int irq) -{ - struct irq_node *node; - kstat_cpu(0).irqs[irq]++; - node = irq_list[irq]; - do { - node->handler(irq, node->dev_id); - node = node->next; - } while (node); -} - -asmlinkage void __m68k_handle_int(unsigned int irq, struct pt_regs *regs) -{ - struct pt_regs *old_regs; - old_regs = set_irq_regs(regs); - m68k_handle_int(irq); - set_irq_regs(old_regs); -} asmlinkage void handle_badint(struct pt_regs *regs) { - kstat_cpu(0).irqs[0]++; - printk("unexpected interrupt from %u\n", regs->vector); -} - -int show_interrupts(struct seq_file *p, void *v) -{ - struct irq_controller *contr; - struct irq_node *node; - int i = *(loff_t *) v; - - /* autovector interrupts */ - if (irq_list[i]) { - contr = irq_controller[i]; - node = irq_list[i]; - seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); - while ((node = node->next)) - seq_printf(p, ", %s", node->devname); - seq_puts(p, "\n"); - } - return 0; -} - -#ifdef CONFIG_PROC_FS -void init_irq_proc(void) -{ - /* Insert /proc/irq driver here */ + atomic_inc(&irq_err_count); + pr_warn("unexpected interrupt from %u\n", regs->vector); } -#endif diff --git a/arch/m68k/kernel/irq.c b/arch/m68k/kernel/irq.c index 544b8717d49..c73988cfa90 100644 --- a/arch/m68k/kernel/irq.c +++ b/arch/m68k/kernel/irq.c @@ -28,3 +28,13 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) set_irq_regs(oldregs); } + + +/* The number of spurious interrupts */ +atomic_t irq_err_count; + +int arch_show_interrupts(struct seq_file *p, int prec) +{ + seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); + return 0; +} diff --git a/arch/m68k/kernel/module.c b/arch/m68k/kernel/module.c index 7ea203ce6b1..34849c4c6e3 100644 --- a/arch/m68k/kernel/module.c +++ b/arch/m68k/kernel/module.c @@ -1,5 +1,129 @@ -#ifdef CONFIG_MMU -#include "module_mm.c" +/* + * 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. + */ + +#include <linux/moduleloader.h> +#include <linux/elf.h> +#include <linux/vmalloc.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> + +#if 0 +#define DEBUGP printk #else -#include "module_no.c" +#define DEBUGP(fmt...) +#endif + +#ifdef CONFIG_MODULES + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location; + + DEBUGP("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. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + + switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_68K_32: + /* We add the value into the location given */ + *location += sym->st_value; + break; + case R_68K_PC32: + /* Add the value, subtract its postition */ + *location += sym->st_value - (uint32_t)location; + break; + default: + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + me->name, ELF32_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + return 0; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location; + + DEBUGP("Applying relocate_add 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. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + + switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_68K_32: + /* We add the value into the location given */ + *location = rel[i].r_addend + sym->st_value; + break; + case R_68K_PC32: + /* Add the value, subtract its postition */ + *location = rel[i].r_addend + sym->st_value - (uint32_t)location; + break; + default: + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + me->name, ELF32_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + return 0; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *mod) +{ + module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end); + return 0; +} + +#endif /* CONFIG_MODULES */ + +void module_fixup(struct module *mod, struct m68k_fixup_info *start, + struct m68k_fixup_info *end) +{ +#ifdef CONFIG_MMU + struct m68k_fixup_info *fixup; + + for (fixup = start; fixup < end; fixup++) { + switch (fixup->type) { + case m68k_fixup_memoffset: + *(u32 *)fixup->addr = m68k_memoffset; + break; + case m68k_fixup_vnode_shift: + *(u16 *)fixup->addr += m68k_virt_to_node_shift; + break; + } + } #endif +} diff --git a/arch/m68k/kernel/module_mm.c b/arch/m68k/kernel/module_mm.c deleted file mode 100644 index cd6bcb1c957..00000000000 --- a/arch/m68k/kernel/module_mm.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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. - */ - -#include <linux/moduleloader.h> -#include <linux/elf.h> -#include <linux/vmalloc.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/kernel.h> - -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(fmt...) -#endif - -#ifdef CONFIG_MODULES - -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); -} - -/* We don't need anything special. */ -int module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod) -{ - return 0; -} - -int apply_relocate(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - unsigned int i; - Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; - Elf32_Sym *sym; - uint32_t *location; - - DEBUGP("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. Note that all - undefined symbols have been resolved. */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_addr - + ELF32_R_SYM(rel[i].r_info); - - switch (ELF32_R_TYPE(rel[i].r_info)) { - case R_68K_32: - /* We add the value into the location given */ - *location += sym->st_value; - break; - case R_68K_PC32: - /* Add the value, subtract its postition */ - *location += sym->st_value - (uint32_t)location; - break; - default: - printk(KERN_ERR "module %s: Unknown relocation: %u\n", - me->name, ELF32_R_TYPE(rel[i].r_info)); - return -ENOEXEC; - } - } - return 0; -} - -int apply_relocate_add(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - unsigned int i; - Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; - Elf32_Sym *sym; - uint32_t *location; - - DEBUGP("Applying relocate_add 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. Note that all - undefined symbols have been resolved. */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_addr - + ELF32_R_SYM(rel[i].r_info); - - switch (ELF32_R_TYPE(rel[i].r_info)) { - case R_68K_32: - /* We add the value into the location given */ - *location = rel[i].r_addend + sym->st_value; - break; - case R_68K_PC32: - /* Add the value, subtract its postition */ - *location = rel[i].r_addend + sym->st_value - (uint32_t)location; - break; - default: - printk(KERN_ERR "module %s: Unknown relocation: %u\n", - me->name, ELF32_R_TYPE(rel[i].r_info)); - return -ENOEXEC; - } - } - return 0; -} - -int module_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - struct module *mod) -{ - module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end); - - return 0; -} - -void module_arch_cleanup(struct module *mod) -{ -} - -#endif /* CONFIG_MODULES */ - -void module_fixup(struct module *mod, struct m68k_fixup_info *start, - struct m68k_fixup_info *end) -{ - struct m68k_fixup_info *fixup; - - for (fixup = start; fixup < end; fixup++) { - switch (fixup->type) { - case m68k_fixup_memoffset: - *(u32 *)fixup->addr = m68k_memoffset; - break; - case m68k_fixup_vnode_shift: - *(u16 *)fixup->addr += m68k_virt_to_node_shift; - break; - } - } -} diff --git a/arch/m68k/kernel/module_no.c b/arch/m68k/kernel/module_no.c deleted file mode 100644 index d11ffae7956..00000000000 --- a/arch/m68k/kernel/module_no.c +++ /dev/null @@ -1,126 +0,0 @@ -#include <linux/moduleloader.h> -#include <linux/elf.h> -#include <linux/vmalloc.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/kernel.h> - -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(fmt...) -#endif - -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); -} - -/* We don't need anything special. */ -int module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod) -{ - return 0; -} - -int apply_relocate(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - unsigned int i; - Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; - Elf32_Sym *sym; - uint32_t *location; - - DEBUGP("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. Note that all - undefined symbols have been resolved. */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_addr - + ELF32_R_SYM(rel[i].r_info); - - switch (ELF32_R_TYPE(rel[i].r_info)) { - case R_68K_32: - /* We add the value into the location given */ - *location += sym->st_value; - break; - case R_68K_PC32: - /* Add the value, subtract its postition */ - *location += sym->st_value - (uint32_t)location; - break; - default: - printk(KERN_ERR "module %s: Unknown relocation: %u\n", - me->name, ELF32_R_TYPE(rel[i].r_info)); - return -ENOEXEC; - } - } - return 0; -} - -int apply_relocate_add(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - unsigned int i; - Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; - Elf32_Sym *sym; - uint32_t *location; - - DEBUGP("Applying relocate_add 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. Note that all - undefined symbols have been resolved. */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_addr - + ELF32_R_SYM(rel[i].r_info); - - switch (ELF32_R_TYPE(rel[i].r_info)) { - case R_68K_32: - /* We add the value into the location given */ - *location = rel[i].r_addend + sym->st_value; - break; - case R_68K_PC32: - /* Add the value, subtract its postition */ - *location = rel[i].r_addend + sym->st_value - (uint32_t)location; - break; - default: - printk(KERN_ERR "module %s: Unknown relocation: %u\n", - me->name, ELF32_R_TYPE(rel[i].r_info)); - return -ENOEXEC; - } - } - return 0; -} - -int module_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - struct module *me) -{ - return 0; -} - -void module_arch_cleanup(struct module *mod) -{ -} diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c index c2a1fc23dd7..1bc223aa07e 100644 --- a/arch/m68k/kernel/process_mm.c +++ b/arch/m68k/kernel/process_mm.c @@ -185,7 +185,7 @@ EXPORT_SYMBOL(kernel_thread); void flush_thread(void) { unsigned long zero = 0; - set_fs(USER_DS); + current->thread.fs = __USER_DS; if (!FPU_IS_EMU) asm volatile (".chip 68k/68881\n\t" diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c index 9b86ad11c68..69c1803fcf1 100644 --- a/arch/m68k/kernel/process_no.c +++ b/arch/m68k/kernel/process_no.c @@ -158,7 +158,7 @@ void flush_thread(void) #ifdef CONFIG_FPU unsigned long zero = 0; #endif - set_fs(USER_DS); + current->thread.fs = __USER_DS; #ifdef CONFIG_FPU if (!FPU_IS_EMU) diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c index 334d8364037..c3b45061dd0 100644 --- a/arch/m68k/kernel/setup_mm.c +++ b/arch/m68k/kernel/setup_mm.c @@ -216,7 +216,9 @@ static void __init m68k_parse_bootinfo(const struct bi_record *record) void __init setup_arch(char **cmdline_p) { +#ifndef CONFIG_SUN3 int i; +#endif /* The bootinfo is located right after the kernel bss */ m68k_parse_bootinfo((const struct bi_record *)_end); diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c index 16b2de7f510..2ed8c0fb151 100644 --- a/arch/m68k/kernel/setup_no.c +++ b/arch/m68k/kernel/setup_no.c @@ -36,6 +36,7 @@ #include <asm/irq.h> #include <asm/machdep.h> #include <asm/pgtable.h> +#include <asm/sections.h> unsigned long memory_start; unsigned long memory_end; @@ -80,9 +81,6 @@ void (*mach_power_off)(void); #define CPU_INSTR_PER_JIFFY 16 #endif -extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; -extern int _ramstart, _ramend; - #if defined(CONFIG_UBOOT) /* * parse_uboot_commandline diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 00d1452f957..c468f2edaa8 100644 --- a/arch/m68k/kernel/syscalltable.S +++ b/arch/m68k/kernel/syscalltable.S @@ -189,7 +189,7 @@ ENTRY(sys_call_table) .long sys_getpagesize .long sys_ni_syscall /* old "query_module" */ .long sys_poll - .long sys_nfsservctl + .long sys_ni_syscall /* old nfsservctl */ .long sys_setresgid16 /* 170 */ .long sys_getresgid16 .long sys_prctl diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index c98add3f5f0..89362f2bb56 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -1,5 +1,1107 @@ -#ifdef CONFIG_MMU -#include "traps_mm.c" +/* + * linux/arch/m68k/kernel/traps.c + * + * Copyright (C) 1993, 1994 by Hamish Macdonald + * + * 68040 fixes by Michael Rausch + * 68040 fixes by Martin Apel + * 68040 fixes and writeback by Richard Zidlicky + * 68060 fixes by Roman Hodek + * 68060 fixes by Jesper Skov + * + * 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. + */ + +/* + * Sets up all exception vectors + */ + +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/user.h> +#include <linux/string.h> +#include <linux/linkage.h> +#include <linux/init.h> +#include <linux/ptrace.h> +#include <linux/kallsyms.h> + +#include <asm/setup.h> +#include <asm/fpu.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/traps.h> +#include <asm/pgalloc.h> +#include <asm/machdep.h> +#include <asm/siginfo.h> + + +static const char *vec_names[] = { + [VEC_RESETSP] = "RESET SP", + [VEC_RESETPC] = "RESET PC", + [VEC_BUSERR] = "BUS ERROR", + [VEC_ADDRERR] = "ADDRESS ERROR", + [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION", + [VEC_ZERODIV] = "ZERO DIVIDE", + [VEC_CHK] = "CHK", + [VEC_TRAP] = "TRAPcc", + [VEC_PRIV] = "PRIVILEGE VIOLATION", + [VEC_TRACE] = "TRACE", + [VEC_LINE10] = "LINE 1010", + [VEC_LINE11] = "LINE 1111", + [VEC_RESV12] = "UNASSIGNED RESERVED 12", + [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION", + [VEC_FORMAT] = "FORMAT ERROR", + [VEC_UNINT] = "UNINITIALIZED INTERRUPT", + [VEC_RESV16] = "UNASSIGNED RESERVED 16", + [VEC_RESV17] = "UNASSIGNED RESERVED 17", + [VEC_RESV18] = "UNASSIGNED RESERVED 18", + [VEC_RESV19] = "UNASSIGNED RESERVED 19", + [VEC_RESV20] = "UNASSIGNED RESERVED 20", + [VEC_RESV21] = "UNASSIGNED RESERVED 21", + [VEC_RESV22] = "UNASSIGNED RESERVED 22", + [VEC_RESV23] = "UNASSIGNED RESERVED 23", + [VEC_SPUR] = "SPURIOUS INTERRUPT", + [VEC_INT1] = "LEVEL 1 INT", + [VEC_INT2] = "LEVEL 2 INT", + [VEC_INT3] = "LEVEL 3 INT", + [VEC_INT4] = "LEVEL 4 INT", + [VEC_INT5] = "LEVEL 5 INT", + [VEC_INT6] = "LEVEL 6 INT", + [VEC_INT7] = "LEVEL 7 INT", + [VEC_SYS] = "SYSCALL", + [VEC_TRAP1] = "TRAP #1", + [VEC_TRAP2] = "TRAP #2", + [VEC_TRAP3] = "TRAP #3", + [VEC_TRAP4] = "TRAP #4", + [VEC_TRAP5] = "TRAP #5", + [VEC_TRAP6] = "TRAP #6", + [VEC_TRAP7] = "TRAP #7", + [VEC_TRAP8] = "TRAP #8", + [VEC_TRAP9] = "TRAP #9", + [VEC_TRAP10] = "TRAP #10", + [VEC_TRAP11] = "TRAP #11", + [VEC_TRAP12] = "TRAP #12", + [VEC_TRAP13] = "TRAP #13", + [VEC_TRAP14] = "TRAP #14", + [VEC_TRAP15] = "TRAP #15", + [VEC_FPBRUC] = "FPCP BSUN", + [VEC_FPIR] = "FPCP INEXACT", + [VEC_FPDIVZ] = "FPCP DIV BY 0", + [VEC_FPUNDER] = "FPCP UNDERFLOW", + [VEC_FPOE] = "FPCP OPERAND ERROR", + [VEC_FPOVER] = "FPCP OVERFLOW", + [VEC_FPNAN] = "FPCP SNAN", + [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION", + [VEC_MMUCFG] = "MMU CONFIGURATION ERROR", + [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR", + [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR", + [VEC_RESV59] = "UNASSIGNED RESERVED 59", + [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60", + [VEC_UNIMPII] = "UNASSIGNED RESERVED 61", + [VEC_RESV62] = "UNASSIGNED RESERVED 62", + [VEC_RESV63] = "UNASSIGNED RESERVED 63", +}; + +static const char *space_names[] = { + [0] = "Space 0", + [USER_DATA] = "User Data", + [USER_PROGRAM] = "User Program", +#ifndef CONFIG_SUN3 + [3] = "Space 3", #else -#include "traps_no.c" + [FC_CONTROL] = "Control", +#endif + [4] = "Space 4", + [SUPER_DATA] = "Super Data", + [SUPER_PROGRAM] = "Super Program", + [CPU_SPACE] = "CPU" +}; + +void die_if_kernel(char *,struct pt_regs *,int); +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code); +int send_fault_sig(struct pt_regs *regs); + +asmlinkage void trap_c(struct frame *fp); + +#if defined (CONFIG_M68060) +static inline void access_error060 (struct frame *fp) +{ + unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */ + +#ifdef DEBUG + printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr); +#endif + + if (fslw & MMU060_BPE) { + /* branch prediction error -> clear branch cache */ + __asm__ __volatile__ ("movec %/cacr,%/d0\n\t" + "orl #0x00400000,%/d0\n\t" + "movec %/d0,%/cacr" + : : : "d0" ); + /* return if there's no other error */ + if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE)) + return; + } + + if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) { + unsigned long errorcode; + unsigned long addr = fp->un.fmt4.effaddr; + + if (fslw & MMU060_MA) + addr = (addr + PAGE_SIZE - 1) & PAGE_MASK; + + errorcode = 1; + if (fslw & MMU060_DESC_ERR) { + __flush_tlb040_one(addr); + errorcode = 0; + } + if (fslw & MMU060_W) + errorcode |= 2; +#ifdef DEBUG + printk("errorcode = %d\n", errorcode ); +#endif + do_page_fault(&fp->ptregs, addr, errorcode); + } else if (fslw & (MMU060_SEE)){ + /* Software Emulation Error. + * fault during mem_read/mem_write in ifpsp060/os.S + */ + send_fault_sig(&fp->ptregs); + } else if (!(fslw & (MMU060_RE|MMU060_WE)) || + send_fault_sig(&fp->ptregs) > 0) { + printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr); + printk( "68060 access error, fslw=%lx\n", fslw ); + trap_c( fp ); + } +} +#endif /* CONFIG_M68060 */ + +#if defined (CONFIG_M68040) +static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs) +{ + unsigned long mmusr; + mm_segment_t old_fs = get_fs(); + + set_fs(MAKE_MM_SEG(wbs)); + + if (iswrite) + asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr)); + else + asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr)); + + asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr)); + + set_fs(old_fs); + + return mmusr; +} + +static inline int do_040writeback1(unsigned short wbs, unsigned long wba, + unsigned long wbd) +{ + int res = 0; + mm_segment_t old_fs = get_fs(); + + /* set_fs can not be moved, otherwise put_user() may oops */ + set_fs(MAKE_MM_SEG(wbs)); + + switch (wbs & WBSIZ_040) { + case BA_SIZE_BYTE: + res = put_user(wbd & 0xff, (char __user *)wba); + break; + case BA_SIZE_WORD: + res = put_user(wbd & 0xffff, (short __user *)wba); + break; + case BA_SIZE_LONG: + res = put_user(wbd, (int __user *)wba); + break; + } + + /* set_fs can not be moved, otherwise put_user() may oops */ + set_fs(old_fs); + + +#ifdef DEBUG + printk("do_040writeback1, res=%d\n",res); +#endif + + return res; +} + +/* after an exception in a writeback the stack frame corresponding + * to that exception is discarded, set a few bits in the old frame + * to simulate what it should look like + */ +static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs) +{ + fp->un.fmt7.faddr = wba; + fp->un.fmt7.ssw = wbs & 0xff; + if (wba != current->thread.faddr) + fp->un.fmt7.ssw |= MA_040; +} + +static inline void do_040writebacks(struct frame *fp) +{ + int res = 0; +#if 0 + if (fp->un.fmt7.wb1s & WBV_040) + printk("access_error040: cannot handle 1st writeback. oops.\n"); +#endif + + if ((fp->un.fmt7.wb2s & WBV_040) && + !(fp->un.fmt7.wb2s & WBTT_040)) { + res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, + fp->un.fmt7.wb2d); + if (res) + fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s); + else + fp->un.fmt7.wb2s = 0; + } + + /* do the 2nd wb only if the first one was successful (except for a kernel wb) */ + if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) { + res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, + fp->un.fmt7.wb3d); + if (res) + { + fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s); + + fp->un.fmt7.wb2s = fp->un.fmt7.wb3s; + fp->un.fmt7.wb3s &= (~WBV_040); + fp->un.fmt7.wb2a = fp->un.fmt7.wb3a; + fp->un.fmt7.wb2d = fp->un.fmt7.wb3d; + } + else + fp->un.fmt7.wb3s = 0; + } + + if (res) + send_fault_sig(&fp->ptregs); +} + +/* + * called from sigreturn(), must ensure userspace code didn't + * manipulate exception frame to circumvent protection, then complete + * pending writebacks + * we just clear TM2 to turn it into a userspace access + */ +asmlinkage void berr_040cleanup(struct frame *fp) +{ + fp->un.fmt7.wb2s &= ~4; + fp->un.fmt7.wb3s &= ~4; + + do_040writebacks(fp); +} + +static inline void access_error040(struct frame *fp) +{ + unsigned short ssw = fp->un.fmt7.ssw; + unsigned long mmusr; + +#ifdef DEBUG + printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr); + printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s, + fp->un.fmt7.wb2s, fp->un.fmt7.wb3s); + printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", + fp->un.fmt7.wb2a, fp->un.fmt7.wb3a, + fp->un.fmt7.wb2d, fp->un.fmt7.wb3d); +#endif + + if (ssw & ATC_040) { + unsigned long addr = fp->un.fmt7.faddr; + unsigned long errorcode; + + /* + * The MMU status has to be determined AFTER the address + * has been corrected if there was a misaligned access (MA). + */ + if (ssw & MA_040) + addr = (addr + 7) & -8; + + /* MMU error, get the MMUSR info for this access */ + mmusr = probe040(!(ssw & RW_040), addr, ssw); +#ifdef DEBUG + printk("mmusr = %lx\n", mmusr); +#endif + errorcode = 1; + if (!(mmusr & MMU_R_040)) { + /* clear the invalid atc entry */ + __flush_tlb040_one(addr); + errorcode = 0; + } + + /* despite what documentation seems to say, RMW + * accesses have always both the LK and RW bits set */ + if (!(ssw & RW_040) || (ssw & LK_040)) + errorcode |= 2; + + if (do_page_fault(&fp->ptregs, addr, errorcode)) { +#ifdef DEBUG + printk("do_page_fault() !=0\n"); +#endif + if (user_mode(&fp->ptregs)){ + /* delay writebacks after signal delivery */ +#ifdef DEBUG + printk(".. was usermode - return\n"); +#endif + return; + } + /* disable writeback into user space from kernel + * (if do_page_fault didn't fix the mapping, + * the writeback won't do good) + */ +disable_wb: +#ifdef DEBUG + printk(".. disabling wb2\n"); +#endif + if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr) + fp->un.fmt7.wb2s &= ~WBV_040; + if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr) + fp->un.fmt7.wb3s &= ~WBV_040; + } + } else { + /* In case of a bus error we either kill the process or expect + * the kernel to catch the fault, which then is also responsible + * for cleaning up the mess. + */ + current->thread.signo = SIGBUS; + current->thread.faddr = fp->un.fmt7.faddr; + if (send_fault_sig(&fp->ptregs) >= 0) + printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw, + fp->un.fmt7.faddr); + goto disable_wb; + } + + do_040writebacks(fp); +} +#endif /* CONFIG_M68040 */ + +#if defined(CONFIG_SUN3) +#include <asm/sun3mmu.h> + +extern int mmu_emu_handle_fault (unsigned long, int, int); + +/* sun3 version of bus_error030 */ + +static inline void bus_error030 (struct frame *fp) +{ + unsigned char buserr_type = sun3_get_buserr (); + unsigned long addr, errorcode; + unsigned short ssw = fp->un.fmtb.ssw; + extern unsigned long _sun3_map_test_start, _sun3_map_test_end; + +#ifdef DEBUG + if (ssw & (FC | FB)) + printk ("Instruction fault at %#010lx\n", + ssw & FC ? + fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 + : + fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); + if (ssw & DF) + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); +#endif + + /* + * Check if this page should be demand-mapped. This needs to go before + * the testing for a bad kernel-space access (demand-mapping applies + * to kernel accesses too). + */ + + if ((ssw & DF) + && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) { + if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0)) + return; + } + + /* Check for kernel-space pagefault (BAD). */ + if (fp->ptregs.sr & PS_S) { + /* kernel fault must be a data fault to user space */ + if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { + // try checking the kernel mappings before surrender + if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1)) + return; + /* instruction fault or kernel data fault! */ + if (ssw & (FC | FB)) + printk ("Instruction fault at %#010lx\n", + fp->ptregs.pc); + if (ssw & DF) { + /* was this fault incurred testing bus mappings? */ + if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) && + (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) { + send_fault_sig(&fp->ptregs); + return; + } + + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); + } + printk ("BAD KERNEL BUSERR\n"); + + die_if_kernel("Oops", &fp->ptregs,0); + force_sig(SIGKILL, current); + return; + } + } else { + /* user fault */ + if (!(ssw & (FC | FB)) && !(ssw & DF)) + /* not an instruction fault or data fault! BAD */ + panic ("USER BUSERR w/o instruction or data fault"); + } + + + /* First handle the data fault, if any. */ + if (ssw & DF) { + addr = fp->un.fmtb.daddr; + +// errorcode bit 0: 0 -> no page 1 -> protection fault +// errorcode bit 1: 0 -> read fault 1 -> write fault + +// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault +// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault + + if (buserr_type & SUN3_BUSERR_PROTERR) + errorcode = 0x01; + else if (buserr_type & SUN3_BUSERR_INVALID) + errorcode = 0x00; + else { +#ifdef DEBUG + printk ("*** unexpected busfault type=%#04x\n", buserr_type); + printk ("invalid %s access at %#lx from pc %#lx\n", + !(ssw & RW) ? "write" : "read", addr, + fp->ptregs.pc); +#endif + die_if_kernel ("Oops", &fp->ptregs, buserr_type); + force_sig (SIGBUS, current); + return; + } + +//todo: wtf is RM bit? --m + if (!(ssw & RW) || ssw & RM) + errorcode |= 0x02; + + /* Handle page fault. */ + do_page_fault (&fp->ptregs, addr, errorcode); + + /* Retry the data fault now. */ + return; + } + + /* Now handle the instruction fault. */ + + /* Get the fault address. */ + if (fp->ptregs.format == 0xA) + addr = fp->ptregs.pc + 4; + else + addr = fp->un.fmtb.baddr; + if (ssw & FC) + addr -= 2; + + if (buserr_type & SUN3_BUSERR_INVALID) { + if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0)) + do_page_fault (&fp->ptregs, addr, 0); + } else { +#ifdef DEBUG + printk ("protection fault on insn access (segv).\n"); +#endif + force_sig (SIGSEGV, current); + } +} +#else +#if defined(CPU_M68020_OR_M68030) +static inline void bus_error030 (struct frame *fp) +{ + volatile unsigned short temp; + unsigned short mmusr; + unsigned long addr, errorcode; + unsigned short ssw = fp->un.fmtb.ssw; +#ifdef DEBUG + unsigned long desc; + + printk ("pid = %x ", current->pid); + printk ("SSW=%#06x ", ssw); + + if (ssw & (FC | FB)) + printk ("Instruction fault at %#010lx\n", + ssw & FC ? + fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 + : + fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); + if (ssw & DF) + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); +#endif + + /* ++andreas: If a data fault and an instruction fault happen + at the same time map in both pages. */ + + /* First handle the data fault, if any. */ + if (ssw & DF) { + addr = fp->un.fmtb.daddr; + +#ifdef DEBUG + asm volatile ("ptestr %3,%2@,#7,%0\n\t" + "pmove %%psr,%1@" + : "=a&" (desc) + : "a" (&temp), "a" (addr), "d" (ssw)); +#else + asm volatile ("ptestr %2,%1@,#7\n\t" + "pmove %%psr,%0@" + : : "a" (&temp), "a" (addr), "d" (ssw)); +#endif + mmusr = temp; + +#ifdef DEBUG + printk("mmusr is %#x for addr %#lx in task %p\n", + mmusr, addr, current); + printk("descriptor address is %#lx, contents %#lx\n", + __va(desc), *(unsigned long *)__va(desc)); +#endif + + errorcode = (mmusr & MMU_I) ? 0 : 1; + if (!(ssw & RW) || (ssw & RM)) + errorcode |= 2; + + if (mmusr & (MMU_I | MMU_WP)) { + if (ssw & 4) { + printk("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, + space_names[ssw & DFC], fp->ptregs.pc); + goto buserr; + } + /* Don't try to do anything further if an exception was + handled. */ + if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) + return; + } else if (!(mmusr & MMU_I)) { + /* probably a 020 cas fault */ + if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0) + printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr); + } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { + printk("invalid %s access at %#lx from pc %#lx\n", + !(ssw & RW) ? "write" : "read", addr, + fp->ptregs.pc); + die_if_kernel("Oops",&fp->ptregs,mmusr); + force_sig(SIGSEGV, current); + return; + } else { +#if 0 + static volatile long tlong; +#endif + + printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", + !(ssw & RW) ? "write" : "read", addr, + fp->ptregs.pc, ssw); + asm volatile ("ptestr #1,%1@,#0\n\t" + "pmove %%psr,%0@" + : /* no outputs */ + : "a" (&temp), "a" (addr)); + mmusr = temp; + + printk ("level 0 mmusr is %#x\n", mmusr); +#if 0 + asm volatile ("pmove %%tt0,%0@" + : /* no outputs */ + : "a" (&tlong)); + printk("tt0 is %#lx, ", tlong); + asm volatile ("pmove %%tt1,%0@" + : /* no outputs */ + : "a" (&tlong)); + printk("tt1 is %#lx\n", tlong); +#endif +#ifdef DEBUG + printk("Unknown SIGSEGV - 1\n"); +#endif + die_if_kernel("Oops",&fp->ptregs,mmusr); + force_sig(SIGSEGV, current); + return; + } + + /* setup an ATC entry for the access about to be retried */ + if (!(ssw & RW) || (ssw & RM)) + asm volatile ("ploadw %1,%0@" : /* no outputs */ + : "a" (addr), "d" (ssw)); + else + asm volatile ("ploadr %1,%0@" : /* no outputs */ + : "a" (addr), "d" (ssw)); + } + + /* Now handle the instruction fault. */ + + if (!(ssw & (FC|FB))) + return; + + if (fp->ptregs.sr & PS_S) { + printk("Instruction fault at %#010lx\n", + fp->ptregs.pc); + buserr: + printk ("BAD KERNEL BUSERR\n"); + die_if_kernel("Oops",&fp->ptregs,0); + force_sig(SIGKILL, current); + return; + } + + /* get the fault address */ + if (fp->ptregs.format == 10) + addr = fp->ptregs.pc + 4; + else + addr = fp->un.fmtb.baddr; + if (ssw & FC) + addr -= 2; + + if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0) + /* Insn fault on same page as data fault. But we + should still create the ATC entry. */ + goto create_atc_entry; + +#ifdef DEBUG + asm volatile ("ptestr #1,%2@,#7,%0\n\t" + "pmove %%psr,%1@" + : "=a&" (desc) + : "a" (&temp), "a" (addr)); +#else + asm volatile ("ptestr #1,%1@,#7\n\t" + "pmove %%psr,%0@" + : : "a" (&temp), "a" (addr)); +#endif + mmusr = temp; + +#ifdef DEBUG + printk ("mmusr is %#x for addr %#lx in task %p\n", + mmusr, addr, current); + printk ("descriptor address is %#lx, contents %#lx\n", + __va(desc), *(unsigned long *)__va(desc)); +#endif + + if (mmusr & MMU_I) + do_page_fault (&fp->ptregs, addr, 0); + else if (mmusr & (MMU_B|MMU_L|MMU_S)) { + printk ("invalid insn access at %#lx from pc %#lx\n", + addr, fp->ptregs.pc); +#ifdef DEBUG + printk("Unknown SIGSEGV - 2\n"); +#endif + die_if_kernel("Oops",&fp->ptregs,mmusr); + force_sig(SIGSEGV, current); + return; + } + +create_atc_entry: + /* setup an ATC entry for the access about to be retried */ + asm volatile ("ploadr #2,%0@" : /* no outputs */ + : "a" (addr)); +} +#endif /* CPU_M68020_OR_M68030 */ +#endif /* !CONFIG_SUN3 */ + +asmlinkage void buserr_c(struct frame *fp) +{ + /* Only set esp0 if coming from user mode */ + if (user_mode(&fp->ptregs)) + current->thread.esp0 = (unsigned long) fp; + +#ifdef DEBUG + printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); +#endif + + switch (fp->ptregs.format) { +#if defined (CONFIG_M68060) + case 4: /* 68060 access error */ + access_error060 (fp); + break; +#endif +#if defined (CONFIG_M68040) + case 0x7: /* 68040 access error */ + access_error040 (fp); + break; +#endif +#if defined (CPU_M68020_OR_M68030) + case 0xa: + case 0xb: + bus_error030 (fp); + break; +#endif + default: + die_if_kernel("bad frame format",&fp->ptregs,0); +#ifdef DEBUG + printk("Unknown SIGSEGV - 4\n"); +#endif + force_sig(SIGSEGV, current); + } +} + + +static int kstack_depth_to_print = 48; + +void show_trace(unsigned long *stack) +{ + unsigned long *endstack; + unsigned long addr; + int i; + + printk("Call Trace:"); + addr = (unsigned long)stack + THREAD_SIZE - 1; + endstack = (unsigned long *)(addr & -THREAD_SIZE); + i = 0; + while (stack + 1 <= endstack) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (__kernel_text_address(addr)) { +#ifndef CONFIG_KALLSYMS + if (i % 5 == 0) + printk("\n "); +#endif + printk(" [<%08lx>] %pS\n", addr, (void *)addr); + i++; + } + } + printk("\n"); +} + +void show_registers(struct pt_regs *regs) +{ + struct frame *fp = (struct frame *)regs; + mm_segment_t old_fs = get_fs(); + u16 c, *cp; + unsigned long addr; + int i; + + print_modules(); + printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc); + printk("SR: %04x SP: %p a2: %08lx\n", regs->sr, regs, regs->a2); + printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", + regs->d0, regs->d1, regs->d2, regs->d3); + printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", + regs->d4, regs->d5, regs->a0, regs->a1); + + printk("Process %s (pid: %d, task=%p)\n", + current->comm, task_pid_nr(current), current); + addr = (unsigned long)&fp->un; + printk("Frame format=%X ", regs->format); + switch (regs->format) { + case 0x2: + printk("instr addr=%08lx\n", fp->un.fmt2.iaddr); + addr += sizeof(fp->un.fmt2); + break; + case 0x3: + printk("eff addr=%08lx\n", fp->un.fmt3.effaddr); + addr += sizeof(fp->un.fmt3); + break; + case 0x4: + printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n" + : "eff addr=%08lx pc=%08lx\n"), + fp->un.fmt4.effaddr, fp->un.fmt4.pc); + addr += sizeof(fp->un.fmt4); + break; + case 0x7: + printk("eff addr=%08lx ssw=%04x faddr=%08lx\n", + fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr); + printk("wb 1 stat/addr/data: %04x %08lx %08lx\n", + fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0); + printk("wb 2 stat/addr/data: %04x %08lx %08lx\n", + fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d); + printk("wb 3 stat/addr/data: %04x %08lx %08lx\n", + fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d); + printk("push data: %08lx %08lx %08lx %08lx\n", + fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2, + fp->un.fmt7.pd3); + addr += sizeof(fp->un.fmt7); + break; + case 0x9: + printk("instr addr=%08lx\n", fp->un.fmt9.iaddr); + addr += sizeof(fp->un.fmt9); + break; + case 0xa: + printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", + fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb, + fp->un.fmta.daddr, fp->un.fmta.dobuf); + addr += sizeof(fp->un.fmta); + break; + case 0xb: + printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", + fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb, + fp->un.fmtb.daddr, fp->un.fmtb.dobuf); + printk("baddr=%08lx dibuf=%08lx ver=%x\n", + fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver); + addr += sizeof(fp->un.fmtb); + break; + default: + printk("\n"); + } + show_stack(NULL, (unsigned long *)addr); + + printk("Code:"); + set_fs(KERNEL_DS); + cp = (u16 *)regs->pc; + for (i = -8; i < 16; i++) { + if (get_user(c, cp + i) && i >= 0) { + printk(" Bad PC value."); + break; + } + printk(i ? " %04x" : " <%04x>", c); + } + set_fs(old_fs); + printk ("\n"); +} + +void show_stack(struct task_struct *task, unsigned long *stack) +{ + unsigned long *p; + unsigned long *endstack; + int i; + + if (!stack) { + if (task) + stack = (unsigned long *)task->thread.esp0; + else + stack = (unsigned long *)&stack; + } + endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE); + + printk("Stack from %08lx:", (unsigned long)stack); + p = stack; + for (i = 0; i < kstack_depth_to_print; i++) { + if (p + 1 > endstack) + break; + if (i % 8 == 0) + printk("\n "); + printk(" %08lx", *p++); + } + printk("\n"); + show_trace(stack); +} + +/* + * The architecture-independent backtrace generator + */ +void dump_stack(void) +{ + unsigned long stack; + + show_trace(&stack); +} + +EXPORT_SYMBOL(dump_stack); + +/* + * The vector number returned in the frame pointer may also contain + * the "fs" (Fault Status) bits on ColdFire. These are in the bottom + * 2 bits, and upper 2 bits. So we need to mask out the real vector + * number before using it in comparisons. You don't need to do this on + * real 68k parts, but it won't hurt either. + */ + +void bad_super_trap (struct frame *fp) +{ + int vector = (fp->ptregs.vector >> 2) & 0xff; + + console_verbose(); + if (vector < ARRAY_SIZE(vec_names)) + printk ("*** %s *** FORMAT=%X\n", + vec_names[vector], + fp->ptregs.format); + else + printk ("*** Exception %d *** FORMAT=%X\n", + vector, fp->ptregs.format); + if (vector == VEC_ADDRERR && CPU_IS_020_OR_030) { + unsigned short ssw = fp->un.fmtb.ssw; + + printk ("SSW=%#06x ", ssw); + + if (ssw & RC) + printk ("Pipe stage C instruction fault at %#010lx\n", + (fp->ptregs.format) == 0xA ? + fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2); + if (ssw & RB) + printk ("Pipe stage B instruction fault at %#010lx\n", + (fp->ptregs.format) == 0xA ? + fp->ptregs.pc + 4 : fp->un.fmtb.baddr); + if (ssw & DF) + printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", + ssw & RW ? "read" : "write", + fp->un.fmtb.daddr, space_names[ssw & DFC], + fp->ptregs.pc); + } + printk ("Current process id is %d\n", task_pid_nr(current)); + die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); +} + +asmlinkage void trap_c(struct frame *fp) +{ + int sig; + int vector = (fp->ptregs.vector >> 2) & 0xff; + siginfo_t info; + + if (fp->ptregs.sr & PS_S) { + if (vector == VEC_TRACE) { + /* traced a trapping instruction on a 68020/30, + * real exception will be executed afterwards. + */ + } else if (!handle_kernel_fault(&fp->ptregs)) + bad_super_trap(fp); + return; + } + + /* send the appropriate signal to the user program */ + switch (vector) { + case VEC_ADDRERR: + info.si_code = BUS_ADRALN; + sig = SIGBUS; + break; + case VEC_ILLEGAL: + case VEC_LINE10: + case VEC_LINE11: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + case VEC_PRIV: + info.si_code = ILL_PRVOPC; + sig = SIGILL; + break; + case VEC_COPROC: + info.si_code = ILL_COPROC; + sig = SIGILL; + break; + case VEC_TRAP1: + case VEC_TRAP2: + case VEC_TRAP3: + case VEC_TRAP4: + case VEC_TRAP5: + case VEC_TRAP6: + case VEC_TRAP7: + case VEC_TRAP8: + case VEC_TRAP9: + case VEC_TRAP10: + case VEC_TRAP11: + case VEC_TRAP12: + case VEC_TRAP13: + case VEC_TRAP14: + info.si_code = ILL_ILLTRP; + sig = SIGILL; + break; + case VEC_FPBRUC: + case VEC_FPOE: + case VEC_FPNAN: + info.si_code = FPE_FLTINV; + sig = SIGFPE; + break; + case VEC_FPIR: + info.si_code = FPE_FLTRES; + sig = SIGFPE; + break; + case VEC_FPDIVZ: + info.si_code = FPE_FLTDIV; + sig = SIGFPE; + break; + case VEC_FPUNDER: + info.si_code = FPE_FLTUND; + sig = SIGFPE; + break; + case VEC_FPOVER: + info.si_code = FPE_FLTOVF; + sig = SIGFPE; + break; + case VEC_ZERODIV: + info.si_code = FPE_INTDIV; + sig = SIGFPE; + break; + case VEC_CHK: + case VEC_TRAP: + info.si_code = FPE_INTOVF; + sig = SIGFPE; + break; + case VEC_TRACE: /* ptrace single step */ + info.si_code = TRAP_TRACE; + sig = SIGTRAP; + break; + case VEC_TRAP15: /* breakpoint */ + info.si_code = TRAP_BRKPT; + sig = SIGTRAP; + break; + default: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + } + info.si_signo = sig; + info.si_errno = 0; + switch (fp->ptregs.format) { + default: + info.si_addr = (void *) fp->ptregs.pc; + break; + case 2: + info.si_addr = (void *) fp->un.fmt2.iaddr; + break; + case 7: + info.si_addr = (void *) fp->un.fmt7.effaddr; + break; + case 9: + info.si_addr = (void *) fp->un.fmt9.iaddr; + break; + case 10: + info.si_addr = (void *) fp->un.fmta.daddr; + break; + case 11: + info.si_addr = (void *) fp->un.fmtb.daddr; + break; + } + force_sig_info (sig, &info, current); +} + +void die_if_kernel (char *str, struct pt_regs *fp, int nr) +{ + if (!(fp->sr & PS_S)) + return; + + console_verbose(); + printk("%s: %08x\n",str,nr); + show_registers(fp); + add_taint(TAINT_DIE); + do_exit(SIGSEGV); +} + +asmlinkage void set_esp0(unsigned long ssp) +{ + current->thread.esp0 = ssp; +} + +/* + * This function is called if an error occur while accessing + * user-space from the fpsp040 code. + */ +asmlinkage void fpsp040_die(void) +{ + do_exit(SIGSEGV); +} + +#ifdef CONFIG_M68KFPU_EMU +asmlinkage void fpemu_signal(int signal, int code, void *addr) +{ + siginfo_t info; + + info.si_signo = signal; + info.si_errno = 0; + info.si_code = code; + info.si_addr = addr; + force_sig_info(signal, &info, current); +} #endif diff --git a/arch/m68k/kernel/traps_mm.c b/arch/m68k/kernel/traps_mm.c deleted file mode 100644 index 4022bbc2887..00000000000 --- a/arch/m68k/kernel/traps_mm.c +++ /dev/null @@ -1,1207 +0,0 @@ -/* - * linux/arch/m68k/kernel/traps.c - * - * Copyright (C) 1993, 1994 by Hamish Macdonald - * - * 68040 fixes by Michael Rausch - * 68040 fixes by Martin Apel - * 68040 fixes and writeback by Richard Zidlicky - * 68060 fixes by Roman Hodek - * 68060 fixes by Jesper Skov - * - * 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. - */ - -/* - * Sets up all exception vectors - */ - -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/user.h> -#include <linux/string.h> -#include <linux/linkage.h> -#include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/kallsyms.h> - -#include <asm/setup.h> -#include <asm/fpu.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/traps.h> -#include <asm/pgalloc.h> -#include <asm/machdep.h> -#include <asm/siginfo.h> - -/* assembler routines */ -asmlinkage void system_call(void); -asmlinkage void buserr(void); -asmlinkage void trap(void); -asmlinkage void nmihandler(void); -#ifdef CONFIG_M68KFPU_EMU -asmlinkage void fpu_emu(void); -#endif - -e_vector vectors[256]; - -/* nmi handler for the Amiga */ -asm(".text\n" - __ALIGN_STR "\n" - "nmihandler: rte"); - -/* - * this must be called very early as the kernel might - * use some instruction that are emulated on the 060 - * and so we're prepared for early probe attempts (e.g. nf_init). - */ -void __init base_trap_init(void) -{ - if (MACH_IS_SUN3X) { - extern e_vector *sun3x_prom_vbr; - - __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr)); - } - - /* setup the exception vector table */ - __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); - - if (CPU_IS_060) { - /* set up ISP entry points */ - asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); - - vectors[VEC_UNIMPII] = unimp_vec; - } - - vectors[VEC_BUSERR] = buserr; - vectors[VEC_ILLEGAL] = trap; - vectors[VEC_SYS] = system_call; -} - -void __init trap_init (void) -{ - int i; - - for (i = VEC_SPUR; i <= VEC_INT7; i++) - vectors[i] = bad_inthandler; - - for (i = 0; i < VEC_USER; i++) - if (!vectors[i]) - vectors[i] = trap; - - for (i = VEC_USER; i < 256; i++) - vectors[i] = bad_inthandler; - -#ifdef CONFIG_M68KFPU_EMU - if (FPU_IS_EMU) - vectors[VEC_LINE11] = fpu_emu; -#endif - - if (CPU_IS_040 && !FPU_IS_EMU) { - /* set up FPSP entry points */ - asmlinkage void dz_vec(void) asm ("dz"); - asmlinkage void inex_vec(void) asm ("inex"); - asmlinkage void ovfl_vec(void) asm ("ovfl"); - asmlinkage void unfl_vec(void) asm ("unfl"); - asmlinkage void snan_vec(void) asm ("snan"); - asmlinkage void operr_vec(void) asm ("operr"); - asmlinkage void bsun_vec(void) asm ("bsun"); - asmlinkage void fline_vec(void) asm ("fline"); - asmlinkage void unsupp_vec(void) asm ("unsupp"); - - vectors[VEC_FPDIVZ] = dz_vec; - vectors[VEC_FPIR] = inex_vec; - vectors[VEC_FPOVER] = ovfl_vec; - vectors[VEC_FPUNDER] = unfl_vec; - vectors[VEC_FPNAN] = snan_vec; - vectors[VEC_FPOE] = operr_vec; - vectors[VEC_FPBRUC] = bsun_vec; - vectors[VEC_LINE11] = fline_vec; - vectors[VEC_FPUNSUP] = unsupp_vec; - } - - if (CPU_IS_060 && !FPU_IS_EMU) { - /* set up IFPSP entry points */ - asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan"); - asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr"); - asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl"); - asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl"); - asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz"); - asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex"); - asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline"); - asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp"); - asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd"); - - vectors[VEC_FPNAN] = snan_vec6; - vectors[VEC_FPOE] = operr_vec6; - vectors[VEC_FPOVER] = ovfl_vec6; - vectors[VEC_FPUNDER] = unfl_vec6; - vectors[VEC_FPDIVZ] = dz_vec6; - vectors[VEC_FPIR] = inex_vec6; - vectors[VEC_LINE11] = fline_vec6; - vectors[VEC_FPUNSUP] = unsupp_vec6; - vectors[VEC_UNIMPEA] = effadd_vec6; - } - - /* if running on an amiga, make the NMI interrupt do nothing */ - if (MACH_IS_AMIGA) { - vectors[VEC_INT7] = nmihandler; - } -} - - -static const char *vec_names[] = { - [VEC_RESETSP] = "RESET SP", - [VEC_RESETPC] = "RESET PC", - [VEC_BUSERR] = "BUS ERROR", - [VEC_ADDRERR] = "ADDRESS ERROR", - [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION", - [VEC_ZERODIV] = "ZERO DIVIDE", - [VEC_CHK] = "CHK", - [VEC_TRAP] = "TRAPcc", - [VEC_PRIV] = "PRIVILEGE VIOLATION", - [VEC_TRACE] = "TRACE", - [VEC_LINE10] = "LINE 1010", - [VEC_LINE11] = "LINE 1111", - [VEC_RESV12] = "UNASSIGNED RESERVED 12", - [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION", - [VEC_FORMAT] = "FORMAT ERROR", - [VEC_UNINT] = "UNINITIALIZED INTERRUPT", - [VEC_RESV16] = "UNASSIGNED RESERVED 16", - [VEC_RESV17] = "UNASSIGNED RESERVED 17", - [VEC_RESV18] = "UNASSIGNED RESERVED 18", - [VEC_RESV19] = "UNASSIGNED RESERVED 19", - [VEC_RESV20] = "UNASSIGNED RESERVED 20", - [VEC_RESV21] = "UNASSIGNED RESERVED 21", - [VEC_RESV22] = "UNASSIGNED RESERVED 22", - [VEC_RESV23] = "UNASSIGNED RESERVED 23", - [VEC_SPUR] = "SPURIOUS INTERRUPT", - [VEC_INT1] = "LEVEL 1 INT", - [VEC_INT2] = "LEVEL 2 INT", - [VEC_INT3] = "LEVEL 3 INT", - [VEC_INT4] = "LEVEL 4 INT", - [VEC_INT5] = "LEVEL 5 INT", - [VEC_INT6] = "LEVEL 6 INT", - [VEC_INT7] = "LEVEL 7 INT", - [VEC_SYS] = "SYSCALL", - [VEC_TRAP1] = "TRAP #1", - [VEC_TRAP2] = "TRAP #2", - [VEC_TRAP3] = "TRAP #3", - [VEC_TRAP4] = "TRAP #4", - [VEC_TRAP5] = "TRAP #5", - [VEC_TRAP6] = "TRAP #6", - [VEC_TRAP7] = "TRAP #7", - [VEC_TRAP8] = "TRAP #8", - [VEC_TRAP9] = "TRAP #9", - [VEC_TRAP10] = "TRAP #10", - [VEC_TRAP11] = "TRAP #11", - [VEC_TRAP12] = "TRAP #12", - [VEC_TRAP13] = "TRAP #13", - [VEC_TRAP14] = "TRAP #14", - [VEC_TRAP15] = "TRAP #15", - [VEC_FPBRUC] = "FPCP BSUN", - [VEC_FPIR] = "FPCP INEXACT", - [VEC_FPDIVZ] = "FPCP DIV BY 0", - [VEC_FPUNDER] = "FPCP UNDERFLOW", - [VEC_FPOE] = "FPCP OPERAND ERROR", - [VEC_FPOVER] = "FPCP OVERFLOW", - [VEC_FPNAN] = "FPCP SNAN", - [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION", - [VEC_MMUCFG] = "MMU CONFIGURATION ERROR", - [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR", - [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR", - [VEC_RESV59] = "UNASSIGNED RESERVED 59", - [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60", - [VEC_UNIMPII] = "UNASSIGNED RESERVED 61", - [VEC_RESV62] = "UNASSIGNED RESERVED 62", - [VEC_RESV63] = "UNASSIGNED RESERVED 63", -}; - -static const char *space_names[] = { - [0] = "Space 0", - [USER_DATA] = "User Data", - [USER_PROGRAM] = "User Program", -#ifndef CONFIG_SUN3 - [3] = "Space 3", -#else - [FC_CONTROL] = "Control", -#endif - [4] = "Space 4", - [SUPER_DATA] = "Super Data", - [SUPER_PROGRAM] = "Super Program", - [CPU_SPACE] = "CPU" -}; - -void die_if_kernel(char *,struct pt_regs *,int); -asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, - unsigned long error_code); -int send_fault_sig(struct pt_regs *regs); - -asmlinkage void trap_c(struct frame *fp); - -#if defined (CONFIG_M68060) -static inline void access_error060 (struct frame *fp) -{ - unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */ - -#ifdef DEBUG - printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr); -#endif - - if (fslw & MMU060_BPE) { - /* branch prediction error -> clear branch cache */ - __asm__ __volatile__ ("movec %/cacr,%/d0\n\t" - "orl #0x00400000,%/d0\n\t" - "movec %/d0,%/cacr" - : : : "d0" ); - /* return if there's no other error */ - if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE)) - return; - } - - if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) { - unsigned long errorcode; - unsigned long addr = fp->un.fmt4.effaddr; - - if (fslw & MMU060_MA) - addr = (addr + PAGE_SIZE - 1) & PAGE_MASK; - - errorcode = 1; - if (fslw & MMU060_DESC_ERR) { - __flush_tlb040_one(addr); - errorcode = 0; - } - if (fslw & MMU060_W) - errorcode |= 2; -#ifdef DEBUG - printk("errorcode = %d\n", errorcode ); -#endif - do_page_fault(&fp->ptregs, addr, errorcode); - } else if (fslw & (MMU060_SEE)){ - /* Software Emulation Error. - * fault during mem_read/mem_write in ifpsp060/os.S - */ - send_fault_sig(&fp->ptregs); - } else if (!(fslw & (MMU060_RE|MMU060_WE)) || - send_fault_sig(&fp->ptregs) > 0) { - printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr); - printk( "68060 access error, fslw=%lx\n", fslw ); - trap_c( fp ); - } -} -#endif /* CONFIG_M68060 */ - -#if defined (CONFIG_M68040) -static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs) -{ - unsigned long mmusr; - mm_segment_t old_fs = get_fs(); - - set_fs(MAKE_MM_SEG(wbs)); - - if (iswrite) - asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr)); - else - asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr)); - - asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr)); - - set_fs(old_fs); - - return mmusr; -} - -static inline int do_040writeback1(unsigned short wbs, unsigned long wba, - unsigned long wbd) -{ - int res = 0; - mm_segment_t old_fs = get_fs(); - - /* set_fs can not be moved, otherwise put_user() may oops */ - set_fs(MAKE_MM_SEG(wbs)); - - switch (wbs & WBSIZ_040) { - case BA_SIZE_BYTE: - res = put_user(wbd & 0xff, (char __user *)wba); - break; - case BA_SIZE_WORD: - res = put_user(wbd & 0xffff, (short __user *)wba); - break; - case BA_SIZE_LONG: - res = put_user(wbd, (int __user *)wba); - break; - } - - /* set_fs can not be moved, otherwise put_user() may oops */ - set_fs(old_fs); - - -#ifdef DEBUG - printk("do_040writeback1, res=%d\n",res); -#endif - - return res; -} - -/* after an exception in a writeback the stack frame corresponding - * to that exception is discarded, set a few bits in the old frame - * to simulate what it should look like - */ -static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs) -{ - fp->un.fmt7.faddr = wba; - fp->un.fmt7.ssw = wbs & 0xff; - if (wba != current->thread.faddr) - fp->un.fmt7.ssw |= MA_040; -} - -static inline void do_040writebacks(struct frame *fp) -{ - int res = 0; -#if 0 - if (fp->un.fmt7.wb1s & WBV_040) - printk("access_error040: cannot handle 1st writeback. oops.\n"); -#endif - - if ((fp->un.fmt7.wb2s & WBV_040) && - !(fp->un.fmt7.wb2s & WBTT_040)) { - res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, - fp->un.fmt7.wb2d); - if (res) - fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s); - else - fp->un.fmt7.wb2s = 0; - } - - /* do the 2nd wb only if the first one was successful (except for a kernel wb) */ - if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) { - res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, - fp->un.fmt7.wb3d); - if (res) - { - fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s); - - fp->un.fmt7.wb2s = fp->un.fmt7.wb3s; - fp->un.fmt7.wb3s &= (~WBV_040); - fp->un.fmt7.wb2a = fp->un.fmt7.wb3a; - fp->un.fmt7.wb2d = fp->un.fmt7.wb3d; - } - else - fp->un.fmt7.wb3s = 0; - } - - if (res) - send_fault_sig(&fp->ptregs); -} - -/* - * called from sigreturn(), must ensure userspace code didn't - * manipulate exception frame to circumvent protection, then complete - * pending writebacks - * we just clear TM2 to turn it into a userspace access - */ -asmlinkage void berr_040cleanup(struct frame *fp) -{ - fp->un.fmt7.wb2s &= ~4; - fp->un.fmt7.wb3s &= ~4; - - do_040writebacks(fp); -} - -static inline void access_error040(struct frame *fp) -{ - unsigned short ssw = fp->un.fmt7.ssw; - unsigned long mmusr; - -#ifdef DEBUG - printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr); - printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s, - fp->un.fmt7.wb2s, fp->un.fmt7.wb3s); - printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", - fp->un.fmt7.wb2a, fp->un.fmt7.wb3a, - fp->un.fmt7.wb2d, fp->un.fmt7.wb3d); -#endif - - if (ssw & ATC_040) { - unsigned long addr = fp->un.fmt7.faddr; - unsigned long errorcode; - - /* - * The MMU status has to be determined AFTER the address - * has been corrected if there was a misaligned access (MA). - */ - if (ssw & MA_040) - addr = (addr + 7) & -8; - - /* MMU error, get the MMUSR info for this access */ - mmusr = probe040(!(ssw & RW_040), addr, ssw); -#ifdef DEBUG - printk("mmusr = %lx\n", mmusr); -#endif - errorcode = 1; - if (!(mmusr & MMU_R_040)) { - /* clear the invalid atc entry */ - __flush_tlb040_one(addr); - errorcode = 0; - } - - /* despite what documentation seems to say, RMW - * accesses have always both the LK and RW bits set */ - if (!(ssw & RW_040) || (ssw & LK_040)) - errorcode |= 2; - - if (do_page_fault(&fp->ptregs, addr, errorcode)) { -#ifdef DEBUG - printk("do_page_fault() !=0\n"); -#endif - if (user_mode(&fp->ptregs)){ - /* delay writebacks after signal delivery */ -#ifdef DEBUG - printk(".. was usermode - return\n"); -#endif - return; - } - /* disable writeback into user space from kernel - * (if do_page_fault didn't fix the mapping, - * the writeback won't do good) - */ -disable_wb: -#ifdef DEBUG - printk(".. disabling wb2\n"); -#endif - if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr) - fp->un.fmt7.wb2s &= ~WBV_040; - if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr) - fp->un.fmt7.wb3s &= ~WBV_040; - } - } else { - /* In case of a bus error we either kill the process or expect - * the kernel to catch the fault, which then is also responsible - * for cleaning up the mess. - */ - current->thread.signo = SIGBUS; - current->thread.faddr = fp->un.fmt7.faddr; - if (send_fault_sig(&fp->ptregs) >= 0) - printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw, - fp->un.fmt7.faddr); - goto disable_wb; - } - - do_040writebacks(fp); -} -#endif /* CONFIG_M68040 */ - -#if defined(CONFIG_SUN3) -#include <asm/sun3mmu.h> - -extern int mmu_emu_handle_fault (unsigned long, int, int); - -/* sun3 version of bus_error030 */ - -static inline void bus_error030 (struct frame *fp) -{ - unsigned char buserr_type = sun3_get_buserr (); - unsigned long addr, errorcode; - unsigned short ssw = fp->un.fmtb.ssw; - extern unsigned long _sun3_map_test_start, _sun3_map_test_end; - -#ifdef DEBUG - if (ssw & (FC | FB)) - printk ("Instruction fault at %#010lx\n", - ssw & FC ? - fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 - : - fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); - if (ssw & DF) - printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", - fp->un.fmtb.daddr, - space_names[ssw & DFC], fp->ptregs.pc); -#endif - - /* - * Check if this page should be demand-mapped. This needs to go before - * the testing for a bad kernel-space access (demand-mapping applies - * to kernel accesses too). - */ - - if ((ssw & DF) - && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) { - if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0)) - return; - } - - /* Check for kernel-space pagefault (BAD). */ - if (fp->ptregs.sr & PS_S) { - /* kernel fault must be a data fault to user space */ - if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { - // try checking the kernel mappings before surrender - if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1)) - return; - /* instruction fault or kernel data fault! */ - if (ssw & (FC | FB)) - printk ("Instruction fault at %#010lx\n", - fp->ptregs.pc); - if (ssw & DF) { - /* was this fault incurred testing bus mappings? */ - if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) && - (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) { - send_fault_sig(&fp->ptregs); - return; - } - - printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", - fp->un.fmtb.daddr, - space_names[ssw & DFC], fp->ptregs.pc); - } - printk ("BAD KERNEL BUSERR\n"); - - die_if_kernel("Oops", &fp->ptregs,0); - force_sig(SIGKILL, current); - return; - } - } else { - /* user fault */ - if (!(ssw & (FC | FB)) && !(ssw & DF)) - /* not an instruction fault or data fault! BAD */ - panic ("USER BUSERR w/o instruction or data fault"); - } - - - /* First handle the data fault, if any. */ - if (ssw & DF) { - addr = fp->un.fmtb.daddr; - -// errorcode bit 0: 0 -> no page 1 -> protection fault -// errorcode bit 1: 0 -> read fault 1 -> write fault - -// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault -// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault - - if (buserr_type & SUN3_BUSERR_PROTERR) - errorcode = 0x01; - else if (buserr_type & SUN3_BUSERR_INVALID) - errorcode = 0x00; - else { -#ifdef DEBUG - printk ("*** unexpected busfault type=%#04x\n", buserr_type); - printk ("invalid %s access at %#lx from pc %#lx\n", - !(ssw & RW) ? "write" : "read", addr, - fp->ptregs.pc); -#endif - die_if_kernel ("Oops", &fp->ptregs, buserr_type); - force_sig (SIGBUS, current); - return; - } - -//todo: wtf is RM bit? --m - if (!(ssw & RW) || ssw & RM) - errorcode |= 0x02; - - /* Handle page fault. */ - do_page_fault (&fp->ptregs, addr, errorcode); - - /* Retry the data fault now. */ - return; - } - - /* Now handle the instruction fault. */ - - /* Get the fault address. */ - if (fp->ptregs.format == 0xA) - addr = fp->ptregs.pc + 4; - else - addr = fp->un.fmtb.baddr; - if (ssw & FC) - addr -= 2; - - if (buserr_type & SUN3_BUSERR_INVALID) { - if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0)) - do_page_fault (&fp->ptregs, addr, 0); - } else { -#ifdef DEBUG - printk ("protection fault on insn access (segv).\n"); -#endif - force_sig (SIGSEGV, current); - } -} -#else -#if defined(CPU_M68020_OR_M68030) -static inline void bus_error030 (struct frame *fp) -{ - volatile unsigned short temp; - unsigned short mmusr; - unsigned long addr, errorcode; - unsigned short ssw = fp->un.fmtb.ssw; -#ifdef DEBUG - unsigned long desc; - - printk ("pid = %x ", current->pid); - printk ("SSW=%#06x ", ssw); - - if (ssw & (FC | FB)) - printk ("Instruction fault at %#010lx\n", - ssw & FC ? - fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 - : - fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); - if (ssw & DF) - printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", - fp->un.fmtb.daddr, - space_names[ssw & DFC], fp->ptregs.pc); -#endif - - /* ++andreas: If a data fault and an instruction fault happen - at the same time map in both pages. */ - - /* First handle the data fault, if any. */ - if (ssw & DF) { - addr = fp->un.fmtb.daddr; - -#ifdef DEBUG - asm volatile ("ptestr %3,%2@,#7,%0\n\t" - "pmove %%psr,%1@" - : "=a&" (desc) - : "a" (&temp), "a" (addr), "d" (ssw)); -#else - asm volatile ("ptestr %2,%1@,#7\n\t" - "pmove %%psr,%0@" - : : "a" (&temp), "a" (addr), "d" (ssw)); -#endif - mmusr = temp; - -#ifdef DEBUG - printk("mmusr is %#x for addr %#lx in task %p\n", - mmusr, addr, current); - printk("descriptor address is %#lx, contents %#lx\n", - __va(desc), *(unsigned long *)__va(desc)); -#endif - - errorcode = (mmusr & MMU_I) ? 0 : 1; - if (!(ssw & RW) || (ssw & RM)) - errorcode |= 2; - - if (mmusr & (MMU_I | MMU_WP)) { - if (ssw & 4) { - printk("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", - fp->un.fmtb.daddr, - space_names[ssw & DFC], fp->ptregs.pc); - goto buserr; - } - /* Don't try to do anything further if an exception was - handled. */ - if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) - return; - } else if (!(mmusr & MMU_I)) { - /* probably a 020 cas fault */ - if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0) - printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr); - } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { - printk("invalid %s access at %#lx from pc %#lx\n", - !(ssw & RW) ? "write" : "read", addr, - fp->ptregs.pc); - die_if_kernel("Oops",&fp->ptregs,mmusr); - force_sig(SIGSEGV, current); - return; - } else { -#if 0 - static volatile long tlong; -#endif - - printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", - !(ssw & RW) ? "write" : "read", addr, - fp->ptregs.pc, ssw); - asm volatile ("ptestr #1,%1@,#0\n\t" - "pmove %%psr,%0@" - : /* no outputs */ - : "a" (&temp), "a" (addr)); - mmusr = temp; - - printk ("level 0 mmusr is %#x\n", mmusr); -#if 0 - asm volatile ("pmove %%tt0,%0@" - : /* no outputs */ - : "a" (&tlong)); - printk("tt0 is %#lx, ", tlong); - asm volatile ("pmove %%tt1,%0@" - : /* no outputs */ - : "a" (&tlong)); - printk("tt1 is %#lx\n", tlong); -#endif -#ifdef DEBUG - printk("Unknown SIGSEGV - 1\n"); -#endif - die_if_kernel("Oops",&fp->ptregs,mmusr); - force_sig(SIGSEGV, current); - return; - } - - /* setup an ATC entry for the access about to be retried */ - if (!(ssw & RW) || (ssw & RM)) - asm volatile ("ploadw %1,%0@" : /* no outputs */ - : "a" (addr), "d" (ssw)); - else - asm volatile ("ploadr %1,%0@" : /* no outputs */ - : "a" (addr), "d" (ssw)); - } - - /* Now handle the instruction fault. */ - - if (!(ssw & (FC|FB))) - return; - - if (fp->ptregs.sr & PS_S) { - printk("Instruction fault at %#010lx\n", - fp->ptregs.pc); - buserr: - printk ("BAD KERNEL BUSERR\n"); - die_if_kernel("Oops",&fp->ptregs,0); - force_sig(SIGKILL, current); - return; - } - - /* get the fault address */ - if (fp->ptregs.format == 10) - addr = fp->ptregs.pc + 4; - else - addr = fp->un.fmtb.baddr; - if (ssw & FC) - addr -= 2; - - if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0) - /* Insn fault on same page as data fault. But we - should still create the ATC entry. */ - goto create_atc_entry; - -#ifdef DEBUG - asm volatile ("ptestr #1,%2@,#7,%0\n\t" - "pmove %%psr,%1@" - : "=a&" (desc) - : "a" (&temp), "a" (addr)); -#else - asm volatile ("ptestr #1,%1@,#7\n\t" - "pmove %%psr,%0@" - : : "a" (&temp), "a" (addr)); -#endif - mmusr = temp; - -#ifdef DEBUG - printk ("mmusr is %#x for addr %#lx in task %p\n", - mmusr, addr, current); - printk ("descriptor address is %#lx, contents %#lx\n", - __va(desc), *(unsigned long *)__va(desc)); -#endif - - if (mmusr & MMU_I) - do_page_fault (&fp->ptregs, addr, 0); - else if (mmusr & (MMU_B|MMU_L|MMU_S)) { - printk ("invalid insn access at %#lx from pc %#lx\n", - addr, fp->ptregs.pc); -#ifdef DEBUG - printk("Unknown SIGSEGV - 2\n"); -#endif - die_if_kernel("Oops",&fp->ptregs,mmusr); - force_sig(SIGSEGV, current); - return; - } - -create_atc_entry: - /* setup an ATC entry for the access about to be retried */ - asm volatile ("ploadr #2,%0@" : /* no outputs */ - : "a" (addr)); -} -#endif /* CPU_M68020_OR_M68030 */ -#endif /* !CONFIG_SUN3 */ - -asmlinkage void buserr_c(struct frame *fp) -{ - /* Only set esp0 if coming from user mode */ - if (user_mode(&fp->ptregs)) - current->thread.esp0 = (unsigned long) fp; - -#ifdef DEBUG - printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); -#endif - - switch (fp->ptregs.format) { -#if defined (CONFIG_M68060) - case 4: /* 68060 access error */ - access_error060 (fp); - break; -#endif -#if defined (CONFIG_M68040) - case 0x7: /* 68040 access error */ - access_error040 (fp); - break; -#endif -#if defined (CPU_M68020_OR_M68030) - case 0xa: - case 0xb: - bus_error030 (fp); - break; -#endif - default: - die_if_kernel("bad frame format",&fp->ptregs,0); -#ifdef DEBUG - printk("Unknown SIGSEGV - 4\n"); -#endif - force_sig(SIGSEGV, current); - } -} - - -static int kstack_depth_to_print = 48; - -void show_trace(unsigned long *stack) -{ - unsigned long *endstack; - unsigned long addr; - int i; - - printk("Call Trace:"); - addr = (unsigned long)stack + THREAD_SIZE - 1; - endstack = (unsigned long *)(addr & -THREAD_SIZE); - i = 0; - while (stack + 1 <= endstack) { - addr = *stack++; - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ - if (__kernel_text_address(addr)) { -#ifndef CONFIG_KALLSYMS - if (i % 5 == 0) - printk("\n "); -#endif - printk(" [<%08lx>] %pS\n", addr, (void *)addr); - i++; - } - } - printk("\n"); -} - -void show_registers(struct pt_regs *regs) -{ - struct frame *fp = (struct frame *)regs; - mm_segment_t old_fs = get_fs(); - u16 c, *cp; - unsigned long addr; - int i; - - print_modules(); - printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc); - printk("SR: %04x SP: %p a2: %08lx\n", regs->sr, regs, regs->a2); - printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", - regs->d0, regs->d1, regs->d2, regs->d3); - printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", - regs->d4, regs->d5, regs->a0, regs->a1); - - printk("Process %s (pid: %d, task=%p)\n", - current->comm, task_pid_nr(current), current); - addr = (unsigned long)&fp->un; - printk("Frame format=%X ", regs->format); - switch (regs->format) { - case 0x2: - printk("instr addr=%08lx\n", fp->un.fmt2.iaddr); - addr += sizeof(fp->un.fmt2); - break; - case 0x3: - printk("eff addr=%08lx\n", fp->un.fmt3.effaddr); - addr += sizeof(fp->un.fmt3); - break; - case 0x4: - printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n" - : "eff addr=%08lx pc=%08lx\n"), - fp->un.fmt4.effaddr, fp->un.fmt4.pc); - addr += sizeof(fp->un.fmt4); - break; - case 0x7: - printk("eff addr=%08lx ssw=%04x faddr=%08lx\n", - fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr); - printk("wb 1 stat/addr/data: %04x %08lx %08lx\n", - fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0); - printk("wb 2 stat/addr/data: %04x %08lx %08lx\n", - fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d); - printk("wb 3 stat/addr/data: %04x %08lx %08lx\n", - fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d); - printk("push data: %08lx %08lx %08lx %08lx\n", - fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2, - fp->un.fmt7.pd3); - addr += sizeof(fp->un.fmt7); - break; - case 0x9: - printk("instr addr=%08lx\n", fp->un.fmt9.iaddr); - addr += sizeof(fp->un.fmt9); - break; - case 0xa: - printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", - fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb, - fp->un.fmta.daddr, fp->un.fmta.dobuf); - addr += sizeof(fp->un.fmta); - break; - case 0xb: - printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", - fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb, - fp->un.fmtb.daddr, fp->un.fmtb.dobuf); - printk("baddr=%08lx dibuf=%08lx ver=%x\n", - fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver); - addr += sizeof(fp->un.fmtb); - break; - default: - printk("\n"); - } - show_stack(NULL, (unsigned long *)addr); - - printk("Code:"); - set_fs(KERNEL_DS); - cp = (u16 *)regs->pc; - for (i = -8; i < 16; i++) { - if (get_user(c, cp + i) && i >= 0) { - printk(" Bad PC value."); - break; - } - printk(i ? " %04x" : " <%04x>", c); - } - set_fs(old_fs); - printk ("\n"); -} - -void show_stack(struct task_struct *task, unsigned long *stack) -{ - unsigned long *p; - unsigned long *endstack; - int i; - - if (!stack) { - if (task) - stack = (unsigned long *)task->thread.esp0; - else - stack = (unsigned long *)&stack; - } - endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE); - - printk("Stack from %08lx:", (unsigned long)stack); - p = stack; - for (i = 0; i < kstack_depth_to_print; i++) { - if (p + 1 > endstack) - break; - if (i % 8 == 0) - printk("\n "); - printk(" %08lx", *p++); - } - printk("\n"); - show_trace(stack); -} - -/* - * The architecture-independent backtrace generator - */ -void dump_stack(void) -{ - unsigned long stack; - - show_trace(&stack); -} - -EXPORT_SYMBOL(dump_stack); - -void bad_super_trap (struct frame *fp) -{ - console_verbose(); - if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names)) - printk ("*** %s *** FORMAT=%X\n", - vec_names[(fp->ptregs.vector) >> 2], - fp->ptregs.format); - else - printk ("*** Exception %d *** FORMAT=%X\n", - (fp->ptregs.vector) >> 2, - fp->ptregs.format); - if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) { - unsigned short ssw = fp->un.fmtb.ssw; - - printk ("SSW=%#06x ", ssw); - - if (ssw & RC) - printk ("Pipe stage C instruction fault at %#010lx\n", - (fp->ptregs.format) == 0xA ? - fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2); - if (ssw & RB) - printk ("Pipe stage B instruction fault at %#010lx\n", - (fp->ptregs.format) == 0xA ? - fp->ptregs.pc + 4 : fp->un.fmtb.baddr); - if (ssw & DF) - printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", - ssw & RW ? "read" : "write", - fp->un.fmtb.daddr, space_names[ssw & DFC], - fp->ptregs.pc); - } - printk ("Current process id is %d\n", task_pid_nr(current)); - die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); -} - -asmlinkage void trap_c(struct frame *fp) -{ - int sig; - siginfo_t info; - - if (fp->ptregs.sr & PS_S) { - if (fp->ptregs.vector == VEC_TRACE << 2) { - /* traced a trapping instruction on a 68020/30, - * real exception will be executed afterwards. - */ - } else if (!handle_kernel_fault(&fp->ptregs)) - bad_super_trap(fp); - return; - } - - /* send the appropriate signal to the user program */ - switch ((fp->ptregs.vector) >> 2) { - case VEC_ADDRERR: - info.si_code = BUS_ADRALN; - sig = SIGBUS; - break; - case VEC_ILLEGAL: - case VEC_LINE10: - case VEC_LINE11: - info.si_code = ILL_ILLOPC; - sig = SIGILL; - break; - case VEC_PRIV: - info.si_code = ILL_PRVOPC; - sig = SIGILL; - break; - case VEC_COPROC: - info.si_code = ILL_COPROC; - sig = SIGILL; - break; - case VEC_TRAP1: - case VEC_TRAP2: - case VEC_TRAP3: - case VEC_TRAP4: - case VEC_TRAP5: - case VEC_TRAP6: - case VEC_TRAP7: - case VEC_TRAP8: - case VEC_TRAP9: - case VEC_TRAP10: - case VEC_TRAP11: - case VEC_TRAP12: - case VEC_TRAP13: - case VEC_TRAP14: - info.si_code = ILL_ILLTRP; - sig = SIGILL; - break; - case VEC_FPBRUC: - case VEC_FPOE: - case VEC_FPNAN: - info.si_code = FPE_FLTINV; - sig = SIGFPE; - break; - case VEC_FPIR: - info.si_code = FPE_FLTRES; - sig = SIGFPE; - break; - case VEC_FPDIVZ: - info.si_code = FPE_FLTDIV; - sig = SIGFPE; - break; - case VEC_FPUNDER: - info.si_code = FPE_FLTUND; - sig = SIGFPE; - break; - case VEC_FPOVER: - info.si_code = FPE_FLTOVF; - sig = SIGFPE; - break; - case VEC_ZERODIV: - info.si_code = FPE_INTDIV; - sig = SIGFPE; - break; - case VEC_CHK: - case VEC_TRAP: - info.si_code = FPE_INTOVF; - sig = SIGFPE; - break; - case VEC_TRACE: /* ptrace single step */ - info.si_code = TRAP_TRACE; - sig = SIGTRAP; - break; - case VEC_TRAP15: /* breakpoint */ - info.si_code = TRAP_BRKPT; - sig = SIGTRAP; - break; - default: - info.si_code = ILL_ILLOPC; - sig = SIGILL; - break; - } - info.si_signo = sig; - info.si_errno = 0; - switch (fp->ptregs.format) { - default: - info.si_addr = (void *) fp->ptregs.pc; - break; - case 2: - info.si_addr = (void *) fp->un.fmt2.iaddr; - break; - case 7: - info.si_addr = (void *) fp->un.fmt7.effaddr; - break; - case 9: - info.si_addr = (void *) fp->un.fmt9.iaddr; - break; - case 10: - info.si_addr = (void *) fp->un.fmta.daddr; - break; - case 11: - info.si_addr = (void *) fp->un.fmtb.daddr; - break; - } - force_sig_info (sig, &info, current); -} - -void die_if_kernel (char *str, struct pt_regs *fp, int nr) -{ - if (!(fp->sr & PS_S)) - return; - - console_verbose(); - printk("%s: %08x\n",str,nr); - show_registers(fp); - add_taint(TAINT_DIE); - do_exit(SIGSEGV); -} - -/* - * This function is called if an error occur while accessing - * user-space from the fpsp040 code. - */ -asmlinkage void fpsp040_die(void) -{ - do_exit(SIGSEGV); -} - -#ifdef CONFIG_M68KFPU_EMU -asmlinkage void fpemu_signal(int signal, int code, void *addr) -{ - siginfo_t info; - - info.si_signo = signal; - info.si_errno = 0; - info.si_code = code; - info.si_addr = addr; - force_sig_info(signal, &info, current); -} -#endif diff --git a/arch/m68k/kernel/traps_no.c b/arch/m68k/kernel/traps_no.c deleted file mode 100644 index a768008dfd0..00000000000 --- a/arch/m68k/kernel/traps_no.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * linux/arch/m68knommu/kernel/traps.c - * - * Copyright (C) 1993, 1994 by Hamish Macdonald - * - * 68040 fixes by Michael Rausch - * 68040 fixes by Martin Apel - * 68060 fixes by Roman Hodek - * 68060 fixes by Jesper Skov - * - * 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. - */ - -/* - * Sets up all exception vectors - */ -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/user.h> -#include <linux/string.h> -#include <linux/linkage.h> -#include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/kallsyms.h> - -#include <asm/setup.h> -#include <asm/fpu.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/traps.h> -#include <asm/pgtable.h> -#include <asm/machdep.h> -#include <asm/siginfo.h> - -static char const * const vec_names[] = { - "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR", - "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc", - "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111", - "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION", - "FORMAT ERROR", "UNINITIALIZED INTERRUPT", - "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17", - "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19", - "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21", - "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23", - "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT", - "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT", - "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3", - "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7", - "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11", - "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15", - "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW", - "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN", - "FPCP UNSUPPORTED OPERATION", - "MMU CONFIGURATION ERROR" -}; - -void __init trap_init(void) -{ -} - -void die_if_kernel(char *str, struct pt_regs *fp, int nr) -{ - if (!(fp->sr & PS_S)) - return; - - console_verbose(); - printk(KERN_EMERG "%s: %08x\n",str,nr); - printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n", - fp->pc, fp->sr, fp, fp->a2); - printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", - fp->d0, fp->d1, fp->d2, fp->d3); - printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", - fp->d4, fp->d5, fp->a0, fp->a1); - - printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n", - current->comm, current->pid, PAGE_SIZE+(unsigned long)current); - show_stack(NULL, (unsigned long *)(fp + 1)); - add_taint(TAINT_DIE); - do_exit(SIGSEGV); -} - -asmlinkage void buserr_c(struct frame *fp) -{ - /* Only set esp0 if coming from user mode */ - if (user_mode(&fp->ptregs)) - current->thread.esp0 = (unsigned long) fp; - -#if defined(DEBUG) - printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format); -#endif - - die_if_kernel("bad frame format",&fp->ptregs,0); -#if defined(DEBUG) - printk(KERN_DEBUG "Unknown SIGSEGV - 4\n"); -#endif - force_sig(SIGSEGV, current); -} - -static void print_this_address(unsigned long addr, int i) -{ -#ifdef CONFIG_KALLSYMS - printk(KERN_EMERG " [%08lx] ", addr); - print_symbol(KERN_CONT "%s\n", addr); -#else - if (i % 5) - printk(KERN_CONT " [%08lx] ", addr); - else - printk(KERN_EMERG " [%08lx] ", addr); - i++; -#endif -} - -int kstack_depth_to_print = 48; - -static void __show_stack(struct task_struct *task, unsigned long *stack) -{ - unsigned long *endstack, addr; -#ifdef CONFIG_FRAME_POINTER - unsigned long *last_stack; -#endif - int i; - - if (!stack) - stack = (unsigned long *)task->thread.ksp; - - addr = (unsigned long) stack; - endstack = (unsigned long *) PAGE_ALIGN(addr); - - printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); - for (i = 0; i < kstack_depth_to_print; i++) { - if (stack + 1 + i > endstack) - break; - if (i % 8 == 0) - printk(KERN_EMERG " "); - printk(KERN_CONT " %08lx", *(stack + i)); - } - printk("\n"); - i = 0; - -#ifdef CONFIG_FRAME_POINTER - printk(KERN_EMERG "Call Trace:\n"); - - last_stack = stack - 1; - while (stack <= endstack && stack > last_stack) { - - addr = *(stack + 1); - print_this_address(addr, i); - i++; - - last_stack = stack; - stack = (unsigned long *)*stack; - } - printk("\n"); -#else - printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n"); - while (stack <= endstack) { - addr = *stack++; - /* - * If the address is either in the text segment of the kernel, - * or in a region which is occupied by a module then it *may* - * be the address of a calling routine; if so, print it so that - * someone tracing down the cause of the crash will be able to - * figure out the call path that was taken. - */ - if (__kernel_text_address(addr)) { - print_this_address(addr, i); - i++; - } - } - printk(KERN_CONT "\n"); -#endif -} - -void bad_super_trap(struct frame *fp) -{ - int vector = (fp->ptregs.vector >> 2) & 0xff; - - console_verbose(); - if (vector < ARRAY_SIZE(vec_names)) - printk (KERN_WARNING "*** %s *** FORMAT=%X\n", - vec_names[vector], - fp->ptregs.format); - else - printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n", - vector, - fp->ptregs.format); - printk (KERN_WARNING "Current process id is %d\n", current->pid); - die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); -} - -asmlinkage void trap_c(struct frame *fp) -{ - int sig; - int vector = (fp->ptregs.vector >> 2) & 0xff; - siginfo_t info; - - if (fp->ptregs.sr & PS_S) { - if (vector == VEC_TRACE) { - /* traced a trapping instruction */ - } else - bad_super_trap(fp); - return; - } - - /* send the appropriate signal to the user program */ - switch (vector) { - case VEC_ADDRERR: - info.si_code = BUS_ADRALN; - sig = SIGBUS; - break; - case VEC_ILLEGAL: - case VEC_LINE10: - case VEC_LINE11: - info.si_code = ILL_ILLOPC; - sig = SIGILL; - break; - case VEC_PRIV: - info.si_code = ILL_PRVOPC; - sig = SIGILL; - break; - case VEC_COPROC: - info.si_code = ILL_COPROC; - sig = SIGILL; - break; - case VEC_TRAP1: /* gdbserver breakpoint */ - fp->ptregs.pc -= 2; - info.si_code = TRAP_TRACE; - sig = SIGTRAP; - break; - case VEC_TRAP2: - case VEC_TRAP3: - case VEC_TRAP4: - case VEC_TRAP5: - case VEC_TRAP6: - case VEC_TRAP7: - case VEC_TRAP8: - case VEC_TRAP9: - case VEC_TRAP10: - case VEC_TRAP11: - case VEC_TRAP12: - case VEC_TRAP13: - case VEC_TRAP14: - info.si_code = ILL_ILLTRP; - sig = SIGILL; - break; - case VEC_FPBRUC: - case VEC_FPOE: - case VEC_FPNAN: - info.si_code = FPE_FLTINV; - sig = SIGFPE; - break; - case VEC_FPIR: - info.si_code = FPE_FLTRES; - sig = SIGFPE; - break; - case VEC_FPDIVZ: - info.si_code = FPE_FLTDIV; - sig = SIGFPE; - break; - case VEC_FPUNDER: - info.si_code = FPE_FLTUND; - sig = SIGFPE; - break; - case VEC_FPOVER: - info.si_code = FPE_FLTOVF; - sig = SIGFPE; - break; - case VEC_ZERODIV: - info.si_code = FPE_INTDIV; - sig = SIGFPE; - break; - case VEC_CHK: - case VEC_TRAP: - info.si_code = FPE_INTOVF; - sig = SIGFPE; - break; - case VEC_TRACE: /* ptrace single step */ - info.si_code = TRAP_TRACE; - sig = SIGTRAP; - break; - case VEC_TRAP15: /* breakpoint */ - info.si_code = TRAP_BRKPT; - sig = SIGTRAP; - break; - default: - info.si_code = ILL_ILLOPC; - sig = SIGILL; - break; - } - info.si_signo = sig; - info.si_errno = 0; - switch (fp->ptregs.format) { - default: - info.si_addr = (void *) fp->ptregs.pc; - break; - case 2: - info.si_addr = (void *) fp->un.fmt2.iaddr; - break; - case 7: - info.si_addr = (void *) fp->un.fmt7.effaddr; - break; - case 9: - info.si_addr = (void *) fp->un.fmt9.iaddr; - break; - case 10: - info.si_addr = (void *) fp->un.fmta.daddr; - break; - case 11: - info.si_addr = (void *) fp->un.fmtb.daddr; - break; - } - force_sig_info (sig, &info, current); -} - -asmlinkage void set_esp0(unsigned long ssp) -{ - current->thread.esp0 = ssp; -} - -/* - * The architecture-independent backtrace generator - */ -void dump_stack(void) -{ - /* - * We need frame pointers for this little trick, which works as follows: - * - * +------------+ 0x00 - * | Next SP | -> 0x0c - * +------------+ 0x04 - * | Caller | - * +------------+ 0x08 - * | Local vars | -> our stack var - * +------------+ 0x0c - * | Next SP | -> 0x18, that is what we pass to show_stack() - * +------------+ 0x10 - * | Caller | - * +------------+ 0x14 - * | Local vars | - * +------------+ 0x18 - * | ... | - * +------------+ - */ - - unsigned long *stack; - - stack = (unsigned long *)&stack; - stack++; - __show_stack(current, stack); -} -EXPORT_SYMBOL(dump_stack); - -void show_stack(struct task_struct *task, unsigned long *stack) -{ - if (!stack && !task) - dump_stack(); - else - __show_stack(task, stack); -} diff --git a/arch/m68k/kernel/vectors.c b/arch/m68k/kernel/vectors.c new file mode 100644 index 00000000000..147b03fbc71 --- /dev/null +++ b/arch/m68k/kernel/vectors.c @@ -0,0 +1,145 @@ +/* + * vectors.c + * + * Copyright (C) 1993, 1994 by Hamish Macdonald + * + * 68040 fixes by Michael Rausch + * 68040 fixes by Martin Apel + * 68040 fixes and writeback by Richard Zidlicky + * 68060 fixes by Roman Hodek + * 68060 fixes by Jesper Skov + * + * 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. + */ + +/* + * Sets up all exception vectors + */ +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/linkage.h> +#include <linux/init.h> +#include <linux/kallsyms.h> + +#include <asm/setup.h> +#include <asm/fpu.h> +#include <asm/system.h> +#include <asm/traps.h> + +/* assembler routines */ +asmlinkage void system_call(void); +asmlinkage void buserr(void); +asmlinkage void trap(void); +asmlinkage void nmihandler(void); +#ifdef CONFIG_M68KFPU_EMU +asmlinkage void fpu_emu(void); +#endif + +e_vector vectors[256]; + +/* nmi handler for the Amiga */ +asm(".text\n" + __ALIGN_STR "\n" + "nmihandler: rte"); + +/* + * this must be called very early as the kernel might + * use some instruction that are emulated on the 060 + * and so we're prepared for early probe attempts (e.g. nf_init). + */ +void __init base_trap_init(void) +{ + if (MACH_IS_SUN3X) { + extern e_vector *sun3x_prom_vbr; + + __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr)); + } + + /* setup the exception vector table */ + __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); + + if (CPU_IS_060) { + /* set up ISP entry points */ + asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); + + vectors[VEC_UNIMPII] = unimp_vec; + } + + vectors[VEC_BUSERR] = buserr; + vectors[VEC_ILLEGAL] = trap; + vectors[VEC_SYS] = system_call; +} + +void __init trap_init (void) +{ + int i; + + for (i = VEC_SPUR; i <= VEC_INT7; i++) + vectors[i] = bad_inthandler; + + for (i = 0; i < VEC_USER; i++) + if (!vectors[i]) + vectors[i] = trap; + + for (i = VEC_USER; i < 256; i++) + vectors[i] = bad_inthandler; + +#ifdef CONFIG_M68KFPU_EMU + if (FPU_IS_EMU) + vectors[VEC_LINE11] = fpu_emu; +#endif + + if (CPU_IS_040 && !FPU_IS_EMU) { + /* set up FPSP entry points */ + asmlinkage void dz_vec(void) asm ("dz"); + asmlinkage void inex_vec(void) asm ("inex"); + asmlinkage void ovfl_vec(void) asm ("ovfl"); + asmlinkage void unfl_vec(void) asm ("unfl"); + asmlinkage void snan_vec(void) asm ("snan"); + asmlinkage void operr_vec(void) asm ("operr"); + asmlinkage void bsun_vec(void) asm ("bsun"); + asmlinkage void fline_vec(void) asm ("fline"); + asmlinkage void unsupp_vec(void) asm ("unsupp"); + + vectors[VEC_FPDIVZ] = dz_vec; + vectors[VEC_FPIR] = inex_vec; + vectors[VEC_FPOVER] = ovfl_vec; + vectors[VEC_FPUNDER] = unfl_vec; + vectors[VEC_FPNAN] = snan_vec; + vectors[VEC_FPOE] = operr_vec; + vectors[VEC_FPBRUC] = bsun_vec; + vectors[VEC_LINE11] = fline_vec; + vectors[VEC_FPUNSUP] = unsupp_vec; + } + + if (CPU_IS_060 && !FPU_IS_EMU) { + /* set up IFPSP entry points */ + asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan"); + asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr"); + asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl"); + asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl"); + asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz"); + asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex"); + asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline"); + asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp"); + asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd"); + + vectors[VEC_FPNAN] = snan_vec6; + vectors[VEC_FPOE] = operr_vec6; + vectors[VEC_FPOVER] = ovfl_vec6; + vectors[VEC_FPUNDER] = unfl_vec6; + vectors[VEC_FPDIVZ] = dz_vec6; + vectors[VEC_FPIR] = inex_vec6; + vectors[VEC_LINE11] = fline_vec6; + vectors[VEC_FPUNSUP] = unsupp_vec6; + vectors[VEC_UNIMPEA] = effadd_vec6; + } + + /* if running on an amiga, make the NMI interrupt do nothing */ + if (MACH_IS_AMIGA) { + vectors[VEC_INT7] = nmihandler; + } +} + diff --git a/arch/m68k/kernel/vmlinux.lds_no.S b/arch/m68k/kernel/vmlinux.lds_no.S index 7dc4087a954..4e238934083 100644 --- a/arch/m68k/kernel/vmlinux.lds_no.S +++ b/arch/m68k/kernel/vmlinux.lds_no.S @@ -77,7 +77,6 @@ SECTIONS { *(.rodata) *(.rodata.*) *(__vermagic) /* Kernel version magic */ - *(__markers_strings) *(.rodata1) *(.rodata.str1.1) |