Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
  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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
/*
 *  arch/mips/kernel/traps.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.
 */

/*
 * 'traps.c' handles hardware traps and faults after we have saved some
 * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
 * to mainly kill the offending process (probably by giving it a signal,
 * but possibly by killing it outright if necessary).
 *
 * FIXME: This is the place for a fpu emulator.
 */
#include <linux/head.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/timer.h>
#include <linux/mm.h>

#include <asm/vector.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/bootinfo.h>

static inline void console_verbose(void)
{
	extern int console_loglevel;
	console_loglevel = 15;
}

/*
 * Machine specific interrupt handlers
 */
extern asmlinkage void acer_pica_61_handle_int(void);
extern asmlinkage void decstation_handle_int(void);
extern asmlinkage void deskstation_rpc44_handle_int(void);
extern asmlinkage void deskstation_tyne_handle_int(void);
extern asmlinkage void mips_magnum_4000_handle_int(void);

extern asmlinkage void handle_mod(void);
extern asmlinkage void handle_tlbl(void);
extern asmlinkage void handle_tlbs(void);
extern asmlinkage void handle_adel(void);
extern asmlinkage void handle_ades(void);
extern asmlinkage void handle_ibe(void);
extern asmlinkage void handle_dbe(void);
extern asmlinkage void handle_sys(void);
extern asmlinkage void handle_bp(void);
extern asmlinkage void handle_ri(void);
extern asmlinkage void handle_cpu(void);
extern asmlinkage void handle_ov(void);
extern asmlinkage void handle_tr(void);
extern asmlinkage void handle_vcei(void);
extern asmlinkage void handle_fpe(void);
extern asmlinkage void handle_vced(void);
extern asmlinkage void handle_watch(void);
extern asmlinkage void handle_reserved(void);

static char *cpu_names[] = CPU_NAMES;

unsigned long page_colour_mask;

int kstack_depth_to_print = 24;

/*
 * These constant is for searching for possible module text segments.
 * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
 */
#define MODULE_RANGE (8*1024*1024)

void die_if_kernel(char * str, struct pt_regs * regs, long err)
{
	int	i;
	int	*stack;
	u32	*sp, *pc, addr, module_start, module_end;
	extern	char start_kernel, _etext;

	if ((regs->cp0_status & (ST0_ERL|ST0_EXL)) == 0)
		return;

	sp = (u32 *)regs->reg29;
	pc = (u32 *)regs->cp0_epc;

	console_verbose();
	printk("%s: %08lx\n", str, err );

	show_regs(regs);

	/*
	 * Dump the stack
	 */
	if (STACK_MAGIC != *(u32 *)current->kernel_stack_page)
		printk("Corrupted stack page\n");
	printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
		current->comm, current->pid, current->kernel_stack_page);
	for(i=0;i<5;i++)
		printk("%08x ", *sp++);
	stack = (int *) sp;
	for(i=0; i < kstack_depth_to_print; i++) {
		if (((u32) stack & (PAGE_SIZE -1)) == 0)
			break;
		if (i && ((i % 8) == 0))
			printk("\n       ");
		printk("%08lx ", get_user(stack++));
	}
	printk("\nCall Trace: ");
	stack = (int *)sp;
	i = 1;
	module_start = VMALLOC_START;
	module_end = module_start + MODULE_RANGE;
	while (((u32)stack & (PAGE_SIZE -1)) != 0) {
		addr = get_user(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 (((addr >= (u32) &start_kernel) &&
		     (addr <= (u32) &_etext)) ||
		    ((addr >= module_start) && (addr <= module_end))) {
			if (i && ((i % 8) == 0))
				printk("\n       ");
			printk("%08x ", addr);
			i++;
		}
	}

	printk("\nCode : ");
	if ((!verify_area(VERIFY_READ, pc, 5 * sizeof(*pc)) ||
	     KSEGX(pc) == KSEG0 ||
	     KSEGX(pc) == KSEG1) &&
	    (((unsigned long) pc & 3) == 0))
	{
		for(i=0;i<5;i++)
			printk("%08x ", *pc++);
		printk("\n");
	}
	else
		printk("(Bad address in epc)\n");
while(1);
	do_exit(SIGSEGV);
}

static void
fix_ade(struct pt_regs *regs, int write)
{
	printk("Received address error (ade%c)\n", write ? 's' : 'l');
	panic("Fixing address errors not implemented yet");
}

void do_adel(struct pt_regs *regs)
{
	if(current->tss.mflags & MF_FIXADE)
	{
		fix_ade(regs, 0);
		return;
	}
	show_regs(regs);
while(1);
	dump_tlb_nonwired();
	send_sig(SIGSEGV, current, 1);
}

void do_ades(struct pt_regs *regs)
{
	unsigned long	pc = regs->cp0_epc;
	int	i;

	if(current->tss.mflags & MF_FIXADE)
	{
		fix_ade(regs, 1);
		return;
	}
while(1);
	for(i=0; i<NR_TASKS;i++)
		if(task[i] && task[i]->pid >= 2)
		{
			printk("Process %d\n", task[i]->pid);
			dump_list_process(task[i], pc);
		}
	show_regs(regs);
	dump_tlb_nonwired();
	send_sig(SIGSEGV, current, 1);
}

/*
 * The ibe/dbe exceptions are signaled by onboard hardware and should get
 * a board specific handlers to get maximum available information. Bus
 * errors are always symptom of hardware malfunction or a kernel error.
 *
 * FIXME: Linux/68k sends a SIGSEGV for a buserror which seems to be wrong.
 * This is certainly wrong. Actually, all hardware errors (ades,adel,ibe,dbe)
 * are bus errors and therefor should send a SIGBUS! (Andy)
 */
void do_ibe(struct pt_regs *regs)
{
show_regs(regs);
while(1);
	send_sig(SIGBUS, current, 1);
}

void do_dbe(struct pt_regs *regs)
{
show_regs(regs);
while(1);
	send_sig(SIGBUS, current, 1);
}

void do_ov(struct pt_regs *regs)
{
show_regs(regs);
while(1);
	send_sig(SIGFPE, current, 1);
}

void do_fpe(struct pt_regs *regs)
{
show_regs(regs);
while(1);
	send_sig(SIGFPE, current, 1);
}

void do_bp(struct pt_regs *regs)
{
show_regs(regs);
while(1);
	send_sig(SIGILL, current, 1);
}

void do_tr(struct pt_regs *regs)
{
show_regs(regs);
while(1);
	send_sig(SIGILL, current, 1);
}

void do_ri(struct pt_regs *regs)
{
	int	i;

	for(i=0; i<NR_TASKS;i++)
		if(task[i] && task[i]->pid >= 2)
		{
			printk("Process %d\n", task[i]->pid);
			dump_list_process(task[i], 0x7ffff000);
		}
	show_regs(regs);
while(1);
	send_sig(SIGILL, current, 1);
}

void do_cpu(struct pt_regs *regs)
{
	unsigned int cpid;

	cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
	switch(cpid)
	{
	case 1:
		regs->cp0_status |= ST0_CU1;
		break;
	case 0:
		/*
		 * CPU for cp0 can only happen in user mode
		 */
	case 2:
	case 3:
		send_sig(SIGILL, current, 1);
		break;
	}
}

void do_vcei(struct pt_regs *regs)
{
	/*
	 * Only possible on R4[04]00[SM]C. No handler because
	 * I don't have such a cpu.
	 */
	panic("Caught VCEI exception - can't handle yet\n");
}

void do_vced(struct pt_regs *regs)
{
	/*
	 * Only possible on R4[04]00[SM]C. No handler because
	 * I don't have such a cpu.
	 */
	panic("Caught VCED exception - can't handle yet\n");
}

void do_watch(struct pt_regs *regs)
{
	panic("Caught WATCH exception - can't handle yet\n");
}

void do_reserved(struct pt_regs *regs)
{
	/*
	 * Game over - no way to handle this if it ever occurs.
	 * Most probably caused by a new unknown cpu type or
	 * after another deadly hard/software error.
	 */
	panic("Caught reserved exception - can't handle.\n");
}

void trap_init(void)
{
	unsigned long	i;
	void watch_set(unsigned long, unsigned long);

	if(boot_info.machtype == MACH_MIPS_MAGNUM_4000)
		EISA_bus = 1;

	/*
	 * Setup default vectors
	 */
	for (i=0;i<=31;i++)
		set_except_vector(i, handle_reserved);

	/*
	 * Handling the following exceptions depends mostly of the cpu type
	 */
	switch(boot_info.cputype) {
	/*
	 * The R10000 is in most aspects similar to the R4400.  It however
	 * should get some special optimizations.
	 */
	case CPU_R10000:
		write_32bit_cp0_register(CP0_FRAMEMASK, 0);
		set_cp0_status(ST0_XX, ST0_XX);
		page_colour_mask = 0x3000;
		panic("CPU too expensive - making holiday in the ANDES!");
		break;
	case CPU_R4000MC:
	case CPU_R4400MC:
	case CPU_R4000SC:
	case CPU_R4400SC:
		/*
		 * Handlers not implemented yet.  If should ever be used -
		 * otherwise it's a bug in the Linux/MIPS kernel, anyway.
		 */
		set_except_vector(14, handle_vcei);
		set_except_vector(31, handle_vced);
	case CPU_R4000PC:
	case CPU_R4400PC:
	case CPU_R4200:
     /* case CPU_R4300: */
		/*
		 * Use watch exception to trap on access to address zero
		 */
		set_except_vector(23, handle_watch);
		watch_set(KSEG0, 3);
	case CPU_R4600:
		set_except_vector(1, handle_mod);
		set_except_vector(2, handle_tlbl);
		set_except_vector(3, handle_tlbs);
		set_except_vector(4, handle_adel);
		set_except_vector(5, handle_ades);
		/*
		 * The following two are signaled by onboard hardware and
		 * should get board specific handlers to get maximum
		 * available information.
		 */
		set_except_vector(6, handle_ibe);
		set_except_vector(7, handle_dbe);

		set_except_vector(8, handle_sys);
		set_except_vector(9, handle_bp);
		set_except_vector(10, handle_ri);
		set_except_vector(11, handle_cpu);
		set_except_vector(12, handle_ov);
		set_except_vector(13, handle_tr);
		set_except_vector(15, handle_fpe);

		/*
		 * Compute mask for page_colour().  This is based on the
		 * size of the data cache.  Does the size of the icache
		 * need to be accounted for?
		 */
		i = read_32bit_cp0_register(CP0_CONFIG);
		i = (i >> 26) & 7;
		page_colour_mask = 1 << (12 + i);
		break;
	case CPU_R2000:
	case CPU_R3000:
	case CPU_R3000A:
	case CPU_R3041:
	case CPU_R3051:
	case CPU_R3052:
	case CPU_R3081:
	case CPU_R3081E:
	case CPU_R6000:
	case CPU_R6000A:
	case CPU_R8000:
		printk("Detected unsupported CPU type %s.\n",
			cpu_names[boot_info.cputype]);
		panic("Can't handle CPU\n");
		break;

	case CPU_UNKNOWN:
	default:
		panic("Unknown CPU type");
	}

	/*
	 * The interrupt handler mostly depends of the board type.
	 */
	set_except_vector(0, feature->handle_int);
}