File: /usr/src/linux/arch/mips64/sgi-ip22/ip22-berr.c

1     /*
2      * This file is subject to the terms and conditions of the GNU General Public
3      * License.  See the file "COPYING" in the main directory of this archive
4      * for more details.
5      *
6      * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
7      * Copyright (C) 1999, 2000 by Silicon Graphics
8      */
9     #include <linux/init.h>
10     #include <linux/kernel.h>
11     #include <linux/module.h>
12     
13     #include <asm/module.h>
14     #include <asm/uaccess.h>
15     #include <asm/paccess.h>
16     #include <asm/addrspace.h>
17     #include <asm/ptrace.h>
18     
19     extern asmlinkage void handle_ibe(void);
20     extern asmlinkage void handle_dbe(void);
21     
22     extern const struct exception_table_entry __start___dbe_table[];
23     extern const struct exception_table_entry __stop___dbe_table[];
24     
25     static inline unsigned long
26     search_one_table(const struct exception_table_entry *first,
27                      const struct exception_table_entry *last,
28                      unsigned long value)
29     {
30     	while (first <= last) {
31     		const struct exception_table_entry *mid;
32     		long diff;
33     
34     		mid = (last - first) / 2 + first;
35     		diff = mid->insn - value;
36     		if (diff == 0)
37     			return mid->nextinsn;
38     		else if (diff < 0)
39     			first = mid+1;
40     		else
41     			last = mid-1;
42     	}
43     	return 0;
44     }
45     
46     extern spinlock_t modlist_lock;
47     
48     static inline unsigned long
49     search_dbe_table(unsigned long addr)
50     {
51     	unsigned long ret = 0;
52     
53     #ifndef CONFIG_MODULES
54     	/* There is only the kernel to search.  */
55     	ret = search_one_table(__start___dbe_table, __stop___dbe_table-1, addr);
56     	return ret;
57     #else
58     	unsigned long flags;
59     
60     	/* The kernel is the last "module" -- no need to treat it special.  */
61     	struct module *mp;
62     	struct archdata *ap;
63     
64     	spin_lock_irqsave(&modlist_lock, flags);
65     	for (mp = module_list; mp != NULL; mp = mp->next) {
66     		if (!mod_member_present(mp, archdata_end) ||
67             	    !mod_archdata_member_present(mp, struct archdata,
68     						 dbe_table_end))
69     			continue;
70     		ap = (struct archdata *)(mod->archdata_start);
71     
72     		if (ap->dbe_table_start == NULL ||
73     		    !(mp->flags & (MOD_RUNNING | MOD_INITIALIZING)))
74     			continue;
75     		ret = search_one_table(ap->dbe_table_start,
76     				       ap->dbe_table_end - 1, addr);
77     		if (ret)
78     			break;
79     	}
80     	spin_unlock_irqrestore(&modlist_lock, flags);
81     	return ret;
82     #endif
83     }
84     
85     void do_ibe(struct pt_regs *regs)
86     {
87     	printk("Got ibe at 0x%lx\n", regs->cp0_epc);
88     	show_regs(regs);
89     	dump_tlb_addr(regs->cp0_epc);
90     	force_sig(SIGBUS, current);
91     	while(1);
92     }
93     
94     void do_dbe(struct pt_regs *regs)
95     {
96     	unsigned long fixup;
97     
98     	fixup = search_dbe_table(regs->cp0_epc);
99     	if (fixup) {
100     		long new_epc;
101     
102     		new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
103     		regs->cp0_epc = new_epc;
104     		return;
105     	}
106     
107     	printk("Got dbe at 0x%lx\n", regs->cp0_epc);
108     	show_regs(regs);
109     	dump_tlb_all();
110     	while(1);
111     	force_sig(SIGBUS, current);
112     }
113     
114     void __init
115     bus_error_init(void)
116     {
117     	int dummy;
118     
119     	set_except_vector(6, handle_ibe);
120     	set_except_vector(7, handle_dbe);
121     
122     	/* At this time nothing uses the DBE protection mechanism on the
123     	   Indy, so this here is needed to make the kernel link.  */
124     	get_dbe(dummy, (int *)KSEG0);
125     }
126