File: rtl_ex.c

package info (click to toggle)
rtlinux 3.1pre3-3
  • links: PTS
  • area: non-free
  • in suites: etch, etch-m68k
  • size: 4,896 kB
  • ctags: 4,228
  • sloc: ansic: 26,204; sh: 2,069; makefile: 1,414; perl: 855; tcl: 489; asm: 380; cpp: 42
file content (199 lines) | stat: -rw-r--r-- 5,605 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
 * (C) Finite State Machine Labs Inc. 2000 business@fsmlabs.com
 *
 * Released under the terms of GPL 2.
 * Open RTLinux makes use of a patented process described in
 * US Patent 5,995,745. Use of this process is governed
 * by the Open RTLinux Patent License which can be obtained from
 * www.fsmlabs.com/PATENT or by sending email to
 * licensequestions@fsmlabs.com
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <rtl_core.h>
#include <rtl_sync.h>
#include <asm/pgtable.h>
#include <asm/ptrace.h>

#define NR_EXCEPT	6

extern unsigned long rtlinux_do_entIF;
extern unsigned long rtlinux_do_entArith;
extern unsigned long rtlinux_do_page_fault;
extern unsigned long rtlinux_do_entDbg;
extern unsigned long rtlinux_do_entUna;
extern unsigned long rtlinux_sys_call_table;

extern unsigned search_exception_table(unsigned long addr);
extern int rtl_debug_exception(int vector, struct pt_regs *regs);
int (*rtl_intercepter) (int vector, struct pt_regs * regs) = 0;

typedef void (*rtl_trap_handler_t) (struct pt_regs *, long, long);

extern void do_entDbg(unsigned long type, unsigned long a1,
		      unsigned long a2, unsigned long a3, unsigned long a4,
		      unsigned long a5, struct pt_regs regs);

asmlinkage int doentDbg(unsigned long type, unsigned long a1,
			unsigned long a2, unsigned long a3,
			unsigned long a4, unsigned long a5,
			struct pt_regs regs)
{
	return rtl_debug_exception(1, &regs);
}

extern void do_page_fault(unsigned long address, unsigned long mmcsr,
			  long cause, struct pt_regs *regs);

asmlinkage int dopagefault(unsigned long address, unsigned long mmcsr,
			   long cause, struct pt_regs *regs)
{
	if ((regs->pc < PAGE_OFFSET) && !(rtl_is_psc_active()))
		return 0;
	else if (search_exception_table(regs->pc) != 0)
		return 0;
	else
		return rtl_debug_exception(6, regs);
}

extern void do_entArith(unsigned long summary, unsigned long write_mask,
			unsigned long a2, unsigned long a3,
			unsigned long a4, unsigned long a5,
			struct pt_regs regs);

asmlinkage int doArith(unsigned long summary, unsigned long write_mask,
		       unsigned long a2, unsigned long a3,
		       unsigned long a4, unsigned long a5,
		       struct pt_regs regs)
{
	return rtl_debug_exception(7, &regs);
}

extern void do_entIF(unsigned long type, unsigned long a1,
		     unsigned long a2, unsigned long a3, unsigned long a4,
		     unsigned long a5, struct pt_regs regs);

asmlinkage int doIF(unsigned long type, unsigned long a1,
		    unsigned long a2, unsigned long a3, unsigned long a4,
		    unsigned long a5, struct pt_regs regs)
{
	/* i don't know why yet, but apparently the PC and PS get switched
	 * somewhere before we get here.  This switches them back. -Nathan */
	if ((regs.pc == 0) && (regs.ps != 0)) {
		regs.pc = regs.ps;
		regs.ps = 0;
	}
	return rtl_debug_exception(0, &regs);
}

struct allregs {
	unsigned long regs[32];
	unsigned long ps, pc, gp, a0, a1, a2;
};

extern void do_entUna(void *va, unsigned long opcode, unsigned long reg,
		      unsigned long a3, unsigned long a4, unsigned long a5,
		      struct allregs regs);

asmlinkage int doentUna(void *va, unsigned long opcode, unsigned long reg,
			unsigned long a3, unsigned long a4,
			unsigned long a5, struct allregs regs)
{
	/* we have to convert the allregs struct to a pt_regs struct.  How
	 * annoying. -Nathan */
	struct pt_regs real_regs;
	real_regs.pc = regs.pc;
	real_regs.ps = regs.ps;
	real_regs.gp = regs.gp;
	real_regs.trap_a0 = regs.a0;
	real_regs.trap_a1 = regs.a1;
	real_regs.trap_a2 = regs.a2;
	real_regs.r0 = regs.regs[0];
	real_regs.r1 = regs.regs[1];
	real_regs.r2 = regs.regs[2];
	real_regs.r3 = regs.regs[3];
	real_regs.r4 = regs.regs[4];
	real_regs.r5 = regs.regs[5];
	real_regs.r6 = regs.regs[6];
	real_regs.r7 = regs.regs[7];
	real_regs.r8 = regs.regs[8];
	real_regs.r16 = regs.regs[16];
	real_regs.r17 = regs.regs[17];
	real_regs.r18 = regs.regs[18];
	real_regs.r19 = regs.regs[19];
	real_regs.r20 = regs.regs[20];
	real_regs.r21 = regs.regs[21];
	real_regs.r22 = regs.regs[22];
	real_regs.r23 = regs.regs[23];
	real_regs.r24 = regs.regs[24];
	real_regs.r25 = regs.regs[25];
	real_regs.r26 = regs.regs[26];
	real_regs.r27 = regs.regs[27];
	real_regs.r28 = regs.regs[28];
	return rtl_debug_exception(5, &real_regs);
}

extern void sys_call_table(void);

asmlinkage void syscalltable(void)
{
	printk("got system call\n");
	return;
}

int setup_intercept(void)
{
	rtl_irqstate_t flags;

	rtl_no_interrupts(flags);

	rtlinux_do_page_fault = (unsigned long) dopagefault;
	rtlinux_do_entIF = (unsigned long) doIF;
	rtlinux_do_entArith = (unsigned long) doArith;
	rtlinux_do_entDbg = (unsigned long) doentDbg;
	rtlinux_do_entUna = (unsigned long) doentUna;
#if 0
	rtlinux_sys_call_table = (unsigned long) syscalltable;
#endif
	rtl_restore_interrupts(flags);
	return 0;
}

void restore_intercept(void)
{
	rtl_irqstate_t flags;

	rtl_no_interrupts(flags);

	rtlinux_do_entIF = (unsigned long) 0;
	rtlinux_do_entArith = (unsigned long) 0;
	rtlinux_do_page_fault = (unsigned long) 0;
	rtlinux_do_entDbg = (unsigned long) 0;
	rtlinux_do_entUna = (unsigned long) 0;
	rtlinux_sys_call_table = (unsigned long) 0;

	rtl_restore_interrupts(flags);
}

int rtl_request_traps(int (*rtl_exception_intercept)
		       (int vector, struct pt_regs * regs))
{
	if (rtl_exception_intercept) {
		if (rtl_intercepter) {
			return -1;
		} else {
			rtl_intercepter = rtl_exception_intercept;
			setup_intercept();
			return 0;
		}
	} else {
		if (!rtl_intercepter) {
			return -1;
		} else {
			rtl_intercepter = rtl_exception_intercept;
			restore_intercept();
			return 0;
		}
	}
}