traps.c 30.8 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
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
/*
 *  linux/arch/i386/traps.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  Pentium III FXSR, SSE support
 *	Gareth Hughes <gareth@valinux.com>, May 2000
 */

/*
 * 'Traps.c' handles hardware traps and faults after we have saved some
 * state in 'asm.s'.
 */
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/highmem.h>
#include <linux/kallsyms.h>
#include <linux/ptrace.h>
#include <linux/utsname.h>
#include <linux/kprobes.h>
29
#include <linux/kexec.h>
30
#include <linux/unwind.h>
31
#include <linux/uaccess.h>
32
#include <linux/nmi.h>
33
#include <linux/bug.h>
Linus Torvalds's avatar
Linus Torvalds committed
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

#ifdef CONFIG_EISA
#include <linux/ioport.h>
#include <linux/eisa.h>
#endif

#ifdef CONFIG_MCA
#include <linux/mca.h>
#endif

#include <asm/processor.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/debugreg.h>
#include <asm/desc.h>
#include <asm/i387.h>
#include <asm/nmi.h>
52
#include <asm/unwind.h>
Linus Torvalds's avatar
Linus Torvalds committed
53
54
#include <asm/smp.h>
#include <asm/arch_hooks.h>
55
#include <linux/kdebug.h>
56
#include <asm/stacktrace.h>
Linus Torvalds's avatar
Linus Torvalds committed
57
58
59
60
61

#include <linux/module.h>

#include "mach_traps.h"

62
63
int panic_on_unrecovered_nmi;

Linus Torvalds's avatar
Linus Torvalds committed
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
asmlinkage int system_call(void);

/* Do we ignore FPU interrupts ? */
char ignore_fpu_irq = 0;

/*
 * The IDT has to be page-aligned to simplify the Pentium
 * F0 0F bug workaround.. We have a special link segment
 * for this.
 */
struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };

asmlinkage void divide_error(void);
asmlinkage void debug(void);
asmlinkage void nmi(void);
asmlinkage void int3(void);
asmlinkage void overflow(void);
asmlinkage void bounds(void);
asmlinkage void invalid_op(void);
asmlinkage void device_not_available(void);
asmlinkage void coprocessor_segment_overrun(void);
asmlinkage void invalid_TSS(void);
asmlinkage void segment_not_present(void);
asmlinkage void stack_segment(void);
asmlinkage void general_protection(void);
asmlinkage void page_fault(void);
asmlinkage void coprocessor_error(void);
asmlinkage void simd_coprocessor_error(void);
asmlinkage void alignment_check(void);
asmlinkage void spurious_interrupt_bug(void);
asmlinkage void machine_check(void);

96
int kstack_depth_to_print = 24;
97
static unsigned int code_bytes = 64;
98

Linus Torvalds's avatar
Linus Torvalds committed
99
100
101
102
103
104
105
static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
{
	return	p > (void *)tinfo &&
		p < (void *)tinfo + THREAD_SIZE - 3;
}

static inline unsigned long print_context_stack(struct thread_info *tinfo,
106
				unsigned long *stack, unsigned long ebp,
107
				struct stacktrace_ops *ops, void *data)
Linus Torvalds's avatar
Linus Torvalds committed
108
109
110
111
112
{
	unsigned long addr;

#ifdef	CONFIG_FRAME_POINTER
	while (valid_stack_ptr(tinfo, (void *)ebp)) {
113
		unsigned long new_ebp;
Linus Torvalds's avatar
Linus Torvalds committed
114
		addr = *(unsigned long *)(ebp + 4);
115
		ops->address(data, addr);
116
117
		/*
		 * break out of recursive entries (such as
118
119
120
		 * end_of_stack_stop_unwind_function). Also,
		 * we can never allow a frame pointer to
		 * move downwards!
121
	 	 */
122
123
	 	new_ebp = *(unsigned long *)ebp;
		if (new_ebp <= ebp)
124
			break;
125
		ebp = new_ebp;
Linus Torvalds's avatar
Linus Torvalds committed
126
127
128
129
	}
#else
	while (valid_stack_ptr(tinfo, stack)) {
		addr = *stack++;
130
		if (__kernel_text_address(addr))
131
			ops->address(data, addr);
Linus Torvalds's avatar
Linus Torvalds committed
132
133
134
135
136
	}
#endif
	return ebp;
}

137
138
#define MSG(msg) ops->warning(data, msg)

139
140
141
void dump_trace(struct task_struct *task, struct pt_regs *regs,
	        unsigned long *stack,
		struct stacktrace_ops *ops, void *data)
Linus Torvalds's avatar
Linus Torvalds committed
142
{
143
	unsigned long ebp = 0;
Linus Torvalds's avatar
Linus Torvalds committed
144
145
146
147

	if (!task)
		task = current;

148
	if (!stack) {
149
150
151
152
		unsigned long dummy;
		stack = &dummy;
		if (task && task != current)
			stack = (unsigned long *)task->thread.esp;
153
154
	}

155
156
157
158
159
160
161
162
163
#ifdef CONFIG_FRAME_POINTER
	if (!ebp) {
		if (task == current) {
			/* Grab ebp right from our regs */
			asm ("movl %%ebp, %0" : "=r" (ebp) : );
		} else {
			/* ebp is the last reg pushed by switch_to */
			ebp = *(unsigned long *) task->thread.esp;
		}
Linus Torvalds's avatar
Linus Torvalds committed
164
	}
165
#endif
Linus Torvalds's avatar
Linus Torvalds committed
166
167
168
169
170

	while (1) {
		struct thread_info *context;
		context = (struct thread_info *)
			((unsigned long)stack & (~(THREAD_SIZE - 1)));
171
172
173
174
175
176
		ebp = print_context_stack(context, stack, ebp, ops, data);
		/* Should be after the line below, but somewhere
		   in early boot context comes out corrupted and we
		   can't reference it -AK */
		if (ops->stack(data, "IRQ") < 0)
			break;
Linus Torvalds's avatar
Linus Torvalds committed
177
178
179
		stack = (unsigned long*)context->previous_esp;
		if (!stack)
			break;
180
		touch_nmi_watchdog();
Linus Torvalds's avatar
Linus Torvalds committed
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
EXPORT_SYMBOL(dump_trace);

static void
print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
{
	printk(data);
	print_symbol(msg, symbol);
	printk("\n");
}

static void print_trace_warning(void *data, char *msg)
{
	printk("%s%s\n", (char *)data, msg);
}

static int print_trace_stack(void *data, char *name)
{
	return 0;
}

/*
 * Print one address/symbol entries per line.
 */
static void print_trace_address(void *data, unsigned long addr)
{
	printk("%s [<%08lx>] ", (char *)data, addr);
	print_symbol("%s\n", addr);
}

static struct stacktrace_ops print_trace_ops = {
	.warning = print_trace_warning,
	.warning_symbol = print_trace_warning_symbol,
	.stack = print_trace_stack,
	.address = print_trace_address,
};

static void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
		   unsigned long * stack, char *log_lvl)
{
	dump_trace(task, regs, stack, &print_trace_ops, log_lvl);
	printk("%s =======================\n", log_lvl);
}
Linus Torvalds's avatar
Linus Torvalds committed
226

227
228
void show_trace(struct task_struct *task, struct pt_regs *regs,
		unsigned long * stack)
229
{
230
	show_trace_log_lvl(task, regs, stack, "");
231
232
}

233
234
static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
			       unsigned long *esp, char *log_lvl)
Linus Torvalds's avatar
Linus Torvalds committed
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
{
	unsigned long *stack;
	int i;

	if (esp == NULL) {
		if (task)
			esp = (unsigned long*)task->thread.esp;
		else
			esp = (unsigned long *)&esp;
	}

	stack = esp;
	for(i = 0; i < kstack_depth_to_print; i++) {
		if (kstack_end(stack))
			break;
Chuck Ebbert's avatar
Chuck Ebbert committed
250
251
		if (i && ((i % 8) == 0))
			printk("\n%s       ", log_lvl);
Linus Torvalds's avatar
Linus Torvalds committed
252
253
		printk("%08lx ", *stack++);
	}
Chuck Ebbert's avatar
Chuck Ebbert committed
254
	printk("\n%sCall Trace:\n", log_lvl);
255
	show_trace_log_lvl(task, regs, esp, log_lvl);
256
257
258
259
}

void show_stack(struct task_struct *task, unsigned long *esp)
{
Chuck Ebbert's avatar
Chuck Ebbert committed
260
	printk("       ");
261
	show_stack_log_lvl(task, NULL, esp, "");
Linus Torvalds's avatar
Linus Torvalds committed
262
263
264
265
266
267
268
269
270
}

/*
 * The architecture-independent dump_stack generator
 */
void dump_stack(void)
{
	unsigned long stack;

271
	show_trace(current, NULL, &stack);
Linus Torvalds's avatar
Linus Torvalds committed
272
273
274
275
276
277
278
279
280
}

EXPORT_SYMBOL(dump_stack);

void show_registers(struct pt_regs *regs)
{
	int i;
	int in_kernel = 1;
	unsigned long esp;
281
	unsigned short ss, gs;
Linus Torvalds's avatar
Linus Torvalds committed
282
283

	esp = (unsigned long) (&regs->esp);
284
	savesegment(ss, ss);
285
	savesegment(gs, gs);
286
	if (user_mode_vm(regs)) {
Linus Torvalds's avatar
Linus Torvalds committed
287
288
289
290
291
		in_kernel = 0;
		esp = regs->esp;
		ss = regs->xss & 0xffff;
	}
	print_modules();
292
293
294
	printk(KERN_EMERG "CPU:    %d\n"
		KERN_EMERG "EIP:    %04x:[<%08lx>]    %s VLI\n"
		KERN_EMERG "EFLAGS: %08lx   (%s %.*s)\n",
Linus Torvalds's avatar
Linus Torvalds committed
295
		smp_processor_id(), 0xffff & regs->xcs, regs->eip,
296
297
298
		print_tainted(), regs->eflags, init_utsname()->release,
		(int)strcspn(init_utsname()->version, " "),
		init_utsname()->version);
299
300
	print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip);
	printk(KERN_EMERG "eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
Linus Torvalds's avatar
Linus Torvalds committed
301
		regs->eax, regs->ebx, regs->ecx, regs->edx);
302
	printk(KERN_EMERG "esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
Linus Torvalds's avatar
Linus Torvalds committed
303
		regs->esi, regs->edi, regs->ebp, esp);
304
305
	printk(KERN_EMERG "ds: %04x   es: %04x   fs: %04x  gs: %04x  ss: %04x\n",
	       regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss);
306
307
308
	printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
		TASK_COMM_LEN, current->comm, current->pid,
		current_thread_info(), current, current->thread_info);
Linus Torvalds's avatar
Linus Torvalds committed
309
310
311
312
313
	/*
	 * When in-kernel, we also print out the stack and code at the
	 * time of the fault..
	 */
	if (in_kernel) {
314
		u8 *eip;
315
316
		unsigned int code_prologue = code_bytes * 43 / 64;
		unsigned int code_len = code_bytes;
317
		unsigned char c;
Linus Torvalds's avatar
Linus Torvalds committed
318

319
		printk("\n" KERN_EMERG "Stack: ");
320
		show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG);
Linus Torvalds's avatar
Linus Torvalds committed
321

322
		printk(KERN_EMERG "Code: ");
Linus Torvalds's avatar
Linus Torvalds committed
323

324
		eip = (u8 *)regs->eip - code_prologue;
325
326
		if (eip < (u8 *)PAGE_OFFSET ||
			probe_kernel_address(eip, c)) {
327
			/* try starting at EIP */
328
			eip = (u8 *)regs->eip;
329
			code_len = code_len - code_prologue + 1;
330
		}
331
		for (i = 0; i < code_len; i++, eip++) {
332
333
			if (eip < (u8 *)PAGE_OFFSET ||
				probe_kernel_address(eip, c)) {
Linus Torvalds's avatar
Linus Torvalds committed
334
335
336
				printk(" Bad EIP value.");
				break;
			}
337
			if (eip == (u8 *)regs->eip)
Linus Torvalds's avatar
Linus Torvalds committed
338
339
340
341
342
343
344
345
				printk("<%02x> ", c);
			else
				printk("%02x ", c);
		}
	}
	printk("\n");
}	

346
int is_valid_bugaddr(unsigned long eip)
Linus Torvalds's avatar
Linus Torvalds committed
347
348
349
350
{
	unsigned short ud2;

	if (eip < PAGE_OFFSET)
351
		return 0;
352
	if (probe_kernel_address((unsigned short *)eip, ud2))
353
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
354

355
	return ud2 == 0x0b0f;
Linus Torvalds's avatar
Linus Torvalds committed
356
357
}

358
359
360
361
/*
 * This is gone through when something in the kernel has done something bad and
 * is about to be terminated.
 */
Linus Torvalds's avatar
Linus Torvalds committed
362
363
364
365
366
367
368
void die(const char * str, struct pt_regs * regs, long err)
{
	static struct {
		spinlock_t lock;
		u32 lock_owner;
		int lock_owner_depth;
	} die = {
369
		.lock =			__SPIN_LOCK_UNLOCKED(die.lock),
Linus Torvalds's avatar
Linus Torvalds committed
370
371
372
373
		.lock_owner =		-1,
		.lock_owner_depth =	0
	};
	static int die_counter;
374
	unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
375

376
377
	oops_enter();

378
	if (die.lock_owner != raw_smp_processor_id()) {
Linus Torvalds's avatar
Linus Torvalds committed
379
		console_verbose();
380
		spin_lock_irqsave(&die.lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
381
382
383
384
		die.lock_owner = smp_processor_id();
		die.lock_owner_depth = 0;
		bust_spinlocks(1);
	}
385
386
	else
		local_save_flags(flags);
Linus Torvalds's avatar
Linus Torvalds committed
387
388
389

	if (++die.lock_owner_depth < 3) {
		int nl = 0;
390
391
392
		unsigned long esp;
		unsigned short ss;

393
394
		report_bug(regs->eip);

395
		printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
Linus Torvalds's avatar
Linus Torvalds committed
396
#ifdef CONFIG_PREEMPT
397
		printk(KERN_EMERG "PREEMPT ");
Linus Torvalds's avatar
Linus Torvalds committed
398
399
400
		nl = 1;
#endif
#ifdef CONFIG_SMP
401
402
		if (!nl)
			printk(KERN_EMERG);
Linus Torvalds's avatar
Linus Torvalds committed
403
404
405
406
		printk("SMP ");
		nl = 1;
#endif
#ifdef CONFIG_DEBUG_PAGEALLOC
407
408
		if (!nl)
			printk(KERN_EMERG);
Linus Torvalds's avatar
Linus Torvalds committed
409
410
411
412
413
		printk("DEBUG_PAGEALLOC");
		nl = 1;
#endif
		if (nl)
			printk("\n");
414
415
		if (notify_die(DIE_OOPS, str, regs, err,
					current->thread.trap_no, SIGSEGV) !=
416
				NOTIFY_STOP) {
417
			show_registers(regs);
418
419
420
421
422
423
424
425
426
427
428
			/* Executive summary in case the oops scrolled away */
			esp = (unsigned long) (&regs->esp);
			savesegment(ss, ss);
			if (user_mode(regs)) {
				esp = regs->esp;
				ss = regs->xss & 0xffff;
			}
			printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip);
			print_symbol("%s", regs->eip);
			printk(" SS:ESP %04x:%08lx\n", ss, esp);
		}
429
430
		else
			regs = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
431
  	} else
432
		printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
Linus Torvalds's avatar
Linus Torvalds committed
433
434
435

	bust_spinlocks(0);
	die.lock_owner = -1;
436
	spin_unlock_irqrestore(&die.lock, flags);
437

438
439
440
	if (!regs)
		return;

441
442
443
	if (kexec_should_crash(current))
		crash_kexec(regs);

Linus Torvalds's avatar
Linus Torvalds committed
444
445
446
	if (in_interrupt())
		panic("Fatal exception in interrupt");

Horms's avatar
Horms committed
447
	if (panic_on_oops)
448
		panic("Fatal exception");
Horms's avatar
Horms committed
449

450
	oops_exit();
Linus Torvalds's avatar
Linus Torvalds committed
451
452
453
454
455
	do_exit(SIGSEGV);
}

static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
{
456
	if (!user_mode_vm(regs))
Linus Torvalds's avatar
Linus Torvalds committed
457
458
459
		die(str, regs, err);
}

460
461
462
static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
			      struct pt_regs * regs, long error_code,
			      siginfo_t *info)
Linus Torvalds's avatar
Linus Torvalds committed
463
{
464
465
	struct task_struct *tsk = current;

Linus Torvalds's avatar
Linus Torvalds committed
466
467
468
469
470
471
	if (regs->eflags & VM_MASK) {
		if (vm86)
			goto vm86_trap;
		goto trap_signal;
	}

472
	if (!user_mode(regs))
Linus Torvalds's avatar
Linus Torvalds committed
473
474
475
		goto kernel_trap;

	trap_signal: {
476
477
478
479
480
481
482
483
484
485
486
487
		/*
		 * We want error_code and trap_no set for userspace faults and
		 * kernelspace faults which result in die(), but not
		 * kernelspace faults which are fixed up.  die() gives the
		 * process no chance to handle the signal and notice the
		 * kernel fault information, so that won't result in polluting
		 * the information about previously queued, but not yet
		 * delivered, faults.  See also do_general_protection below.
		 */
		tsk->thread.error_code = error_code;
		tsk->thread.trap_no = trapnr;

Linus Torvalds's avatar
Linus Torvalds committed
488
489
490
491
492
493
494
495
		if (info)
			force_sig_info(signr, info, tsk);
		else
			force_sig(signr, tsk);
		return;
	}

	kernel_trap: {
496
497
498
		if (!fixup_exception(regs)) {
			tsk->thread.error_code = error_code;
			tsk->thread.trap_no = trapnr;
Linus Torvalds's avatar
Linus Torvalds committed
499
			die(str, regs, error_code);
500
		}
Linus Torvalds's avatar
Linus Torvalds committed
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
		return;
	}

	vm86_trap: {
		int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr);
		if (ret) goto trap_signal;
		return;
	}
}

#define DO_ERROR(trapnr, signr, str, name) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
						== NOTIFY_STOP) \
		return; \
	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
}

#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
	siginfo_t info; \
	info.si_signo = signr; \
	info.si_errno = 0; \
	info.si_code = sicode; \
	info.si_addr = (void __user *)siaddr; \
	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
						== NOTIFY_STOP) \
		return; \
	do_trap(trapnr, signr, str, 0, regs, error_code, &info); \
}

#define DO_VM86_ERROR(trapnr, signr, str, name) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
						== NOTIFY_STOP) \
		return; \
	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
}

#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
	siginfo_t info; \
	info.si_signo = signr; \
	info.si_errno = 0; \
	info.si_code = sicode; \
	info.si_addr = (void __user *)siaddr; \
	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
						== NOTIFY_STOP) \
		return; \
	do_trap(trapnr, signr, str, 1, regs, error_code, &info); \
}

DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->eip)
#ifndef CONFIG_KPROBES
DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
#endif
DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
563
DO_ERROR_INFO( 6, SIGILL,  "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip)
Linus Torvalds's avatar
Linus Torvalds committed
564
565
566
567
568
DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
569
DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
Linus Torvalds's avatar
Linus Torvalds committed
570

571
572
fastcall void __kprobes do_general_protection(struct pt_regs * regs,
					      long error_code)
Linus Torvalds's avatar
Linus Torvalds committed
573
574
575
576
577
578
579
580
581
582
583
584
{
	int cpu = get_cpu();
	struct tss_struct *tss = &per_cpu(init_tss, cpu);
	struct thread_struct *thread = &current->thread;

	/*
	 * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
	 * invalid offset set (the LAZY one) and the faulting thread has
	 * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS
	 * and we set the offset field correctly. Then we let the CPU to
	 * restart the faulting instruction.
	 */
585
	if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
Linus Torvalds's avatar
Linus Torvalds committed
586
587
588
589
590
591
592
593
594
595
596
597
	    thread->io_bitmap_ptr) {
		memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
		       thread->io_bitmap_max);
		/*
		 * If the previously set map was extending to higher ports
		 * than the current one, pad extra space with 0xff (no access).
		 */
		if (thread->io_bitmap_max < tss->io_bitmap_max)
			memset((char *) tss->io_bitmap +
				thread->io_bitmap_max, 0xff,
				tss->io_bitmap_max - thread->io_bitmap_max);
		tss->io_bitmap_max = thread->io_bitmap_max;
598
		tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
599
		tss->io_bitmap_owner = thread;
Linus Torvalds's avatar
Linus Torvalds committed
600
601
602
603
604
605
606
607
		put_cpu();
		return;
	}
	put_cpu();

	if (regs->eflags & VM_MASK)
		goto gp_in_vm86;

608
	if (!user_mode(regs))
Linus Torvalds's avatar
Linus Torvalds committed
609
610
611
612
613
614
615
616
617
618
619
620
621
622
		goto gp_in_kernel;

	current->thread.error_code = error_code;
	current->thread.trap_no = 13;
	force_sig(SIGSEGV, current);
	return;

gp_in_vm86:
	local_irq_enable();
	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
	return;

gp_in_kernel:
	if (!fixup_exception(regs)) {
623
624
		current->thread.error_code = error_code;
		current->thread.trap_no = 13;
Linus Torvalds's avatar
Linus Torvalds committed
625
626
627
628
629
630
631
		if (notify_die(DIE_GPF, "general protection fault", regs,
				error_code, 13, SIGSEGV) == NOTIFY_STOP)
			return;
		die("general protection fault", regs, error_code);
	}
}

632
633
static __kprobes void
mem_parity_error(unsigned char reason, struct pt_regs * regs)
Linus Torvalds's avatar
Linus Torvalds committed
634
{
635
636
	printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
		"CPU %d.\n", reason, smp_processor_id());
637
	printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
638
639
	if (panic_on_unrecovered_nmi)
                panic("NMI: Not continuing");
Linus Torvalds's avatar
Linus Torvalds committed
640

641
	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
Linus Torvalds's avatar
Linus Torvalds committed
642
643
644
645
646

	/* Clear and disable the memory parity error line. */
	clear_mem_error(reason);
}

647
648
static __kprobes void
io_check_error(unsigned char reason, struct pt_regs * regs)
Linus Torvalds's avatar
Linus Torvalds committed
649
650
651
{
	unsigned long i;

652
	printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
Linus Torvalds's avatar
Linus Torvalds committed
653
654
655
656
657
658
659
660
661
662
663
	show_registers(regs);

	/* Re-enable the IOCK line, wait for a few seconds */
	reason = (reason & 0xf) | 8;
	outb(reason, 0x61);
	i = 2000;
	while (--i) udelay(1000);
	reason &= ~8;
	outb(reason, 0x61);
}

664
665
static __kprobes void
unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
Linus Torvalds's avatar
Linus Torvalds committed
666
667
668
669
670
671
672
673
674
{
#ifdef CONFIG_MCA
	/* Might actually be able to figure out what the guilty party
	* is. */
	if( MCA_bus ) {
		mca_handle_nmi();
		return;
	}
#endif
675
676
677
	printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
		"CPU %d.\n", reason, smp_processor_id());
	printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
678
679
680
	if (panic_on_unrecovered_nmi)
                panic("NMI: Not continuing");

681
	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
Linus Torvalds's avatar
Linus Torvalds committed
682
683
684
685
}

static DEFINE_SPINLOCK(nmi_print_lock);

686
void __kprobes die_nmi(struct pt_regs *regs, const char *msg)
Linus Torvalds's avatar
Linus Torvalds committed
687
{
688
	if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) ==
689
690
691
	    NOTIFY_STOP)
		return;

Linus Torvalds's avatar
Linus Torvalds committed
692
693
694
695
696
697
	spin_lock(&nmi_print_lock);
	/*
	* We are in trouble anyway, lets at least try
	* to get a message out.
	*/
	bust_spinlocks(1);
698
	printk(KERN_EMERG "%s", msg);
Linus Torvalds's avatar
Linus Torvalds committed
699
700
701
702
703
704
	printk(" on CPU%d, eip %08lx, registers:\n",
		smp_processor_id(), regs->eip);
	show_registers(regs);
	console_silent();
	spin_unlock(&nmi_print_lock);
	bust_spinlocks(0);
705
706
707
708

	/* If we are in kernel we are probably nested up pretty bad
	 * and might aswell get out now while we still can.
	*/
709
	if (!user_mode_vm(regs)) {
710
711
712
713
		current->thread.trap_no = 2;
		crash_kexec(regs);
	}

Linus Torvalds's avatar
Linus Torvalds committed
714
715
716
	do_exit(SIGSEGV);
}

717
static __kprobes void default_do_nmi(struct pt_regs * regs)
Linus Torvalds's avatar
Linus Torvalds committed
718
719
720
721
722
723
724
725
{
	unsigned char reason = 0;

	/* Only the BSP gets external NMIs from the system.  */
	if (!smp_processor_id())
		reason = get_nmi_reason();
 
	if (!(reason & 0xc0)) {
726
		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
Linus Torvalds's avatar
Linus Torvalds committed
727
728
729
730
731
732
733
							== NOTIFY_STOP)
			return;
#ifdef CONFIG_X86_LOCAL_APIC
		/*
		 * Ok, so this is none of the documented NMI sources,
		 * so it must be the NMI watchdog.
		 */
734
		if (nmi_watchdog_tick(regs, reason))
Linus Torvalds's avatar
Linus Torvalds committed
735
			return;
736
737
738
739
740
#endif
		if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0)
							== NOTIFY_STOP)
			return;
#ifdef CONFIG_X86_LOCAL_APIC
741
		if (!do_nmi_callback(regs, smp_processor_id()))
Linus Torvalds's avatar
Linus Torvalds committed
742
#endif
743
			unknown_nmi_error(reason, regs);
744

Linus Torvalds's avatar
Linus Torvalds committed
745
746
		return;
	}
747
	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
Linus Torvalds's avatar
Linus Torvalds committed
748
749
750
751
752
753
754
755
756
757
758
759
		return;
	if (reason & 0x80)
		mem_parity_error(reason, regs);
	if (reason & 0x40)
		io_check_error(reason, regs);
	/*
	 * Reassert NMI in case it became active meanwhile
	 * as it's edge-triggered.
	 */
	reassert_nmi();
}

760
fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
Linus Torvalds's avatar
Linus Torvalds committed
761
762
763
764
765
766
{
	int cpu;

	nmi_enter();

	cpu = smp_processor_id();
Zwane Mwaikambo's avatar
Zwane Mwaikambo committed
767

Linus Torvalds's avatar
Linus Torvalds committed
768
769
	++nmi_count(cpu);

770
	default_do_nmi(regs);
Linus Torvalds's avatar
Linus Torvalds committed
771
772
773
774
775

	nmi_exit();
}

#ifdef CONFIG_KPROBES
776
fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
Linus Torvalds's avatar
Linus Torvalds committed
777
778
779
{
	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
			== NOTIFY_STOP)
780
		return;
Linus Torvalds's avatar
Linus Torvalds committed
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
	/* This is an interrupt gate, because kprobes wants interrupts
	disabled.  Normal trap handlers don't. */
	restore_interrupts(regs);
	do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
}
#endif

/*
 * Our handling of the processor debug registers is non-trivial.
 * We do not clear them on entry and exit from the kernel. Therefore
 * it is possible to get a watchpoint trap here from inside the kernel.
 * However, the code in ./ptrace.c has ensured that the user can
 * only set watchpoints on userspace addresses. Therefore the in-kernel
 * watchpoint trap can only occur in code which is reading/writing
 * from user space. Such code must not hold kernel locks (since it
 * can equally take a page fault), therefore it is safe to call
 * force_sig_info even though that claims and releases locks.
 * 
 * Code in ./signal.c ensures that the debug control register
 * is restored before we deliver any signal, and therefore that
 * user code runs with the correct debug control register even though
 * we clear it here.
 *
 * Being careful here means that we don't have to be as careful in a
 * lot of more complicated places (task switching can be a bit lazy
 * about restoring all the debug state, and ptrace doesn't have to
 * find every occurrence of the TF bit that could be saved away even
 * by user code)
 */
810
fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
Linus Torvalds's avatar
Linus Torvalds committed
811
812
813
814
{
	unsigned int condition;
	struct task_struct *tsk = current;

815
	get_debugreg(condition, 6);
Linus Torvalds's avatar
Linus Torvalds committed
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845

	if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
					SIGTRAP) == NOTIFY_STOP)
		return;
	/* It's safe to allow irq's after DR6 has been saved */
	if (regs->eflags & X86_EFLAGS_IF)
		local_irq_enable();

	/* Mask out spurious debug traps due to lazy DR7 setting */
	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
		if (!tsk->thread.debugreg[7])
			goto clear_dr7;
	}

	if (regs->eflags & VM_MASK)
		goto debug_vm86;

	/* Save debug status register where ptrace can see it */
	tsk->thread.debugreg[6] = condition;

	/*
	 * Single-stepping through TF: make sure we ignore any events in
	 * kernel space (but re-enable TF when returning to user mode).
	 */
	if (condition & DR_STEP) {
		/*
		 * We already checked v86 mode above, so we can
		 * check for kernel mode by just checking the CPL
		 * of CS.
		 */
846
		if (!user_mode(regs))
Linus Torvalds's avatar
Linus Torvalds committed
847
848
849
850
851
852
853
854
855
856
			goto clear_TF_reenable;
	}

	/* Ok, finally something we can handle */
	send_sigtrap(tsk, regs, error_code);

	/* Disable additional traps. They'll be re-enabled when
	 * the signal is delivered.
	 */
clear_dr7:
857
	set_debugreg(0, 7);
Linus Torvalds's avatar
Linus Torvalds committed
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
	return;

debug_vm86:
	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
	return;

clear_TF_reenable:
	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
	regs->eflags &= ~TF_MASK;
	return;
}

/*
 * Note that we play around with the 'TS' bit in an attempt to get
 * the correct behaviour even in the presence of the asynchronous
 * IRQ13 behaviour
 */
void math_error(void __user *eip)
{
	struct task_struct * task;
	siginfo_t info;
	unsigned short cwd, swd;

	/*
	 * Save the info for the exception handler and clear the error.
	 */
	task = current;
	save_init_fpu(task);
	task->thread.trap_no = 16;
	task->thread.error_code = 0;
	info.si_signo = SIGFPE;
	info.si_errno = 0;
	info.si_code = __SI_FAULT;
	info.si_addr = eip;
	/*
	 * (~cwd & swd) will mask out exceptions that are not set to unmasked
	 * status.  0x3f is the exception bits in these regs, 0x200 is the
	 * C1 reg you need in case of a stack fault, 0x040 is the stack
	 * fault bit.  We should only be taking one exception at a time,
	 * so if this combination doesn't produce any single exception,
	 * then we have a bad program that isn't syncronizing its FPU usage
	 * and it will suffer the consequences since we won't be able to
	 * fully reproduce the context of the exception
	 */
	cwd = get_fpu_cwd(task);
	swd = get_fpu_swd(task);
904
	switch (swd & ~cwd & 0x3f) {
905
906
907
		case 0x000: /* No unmasked exception */
			return;
		default:    /* Multiple exceptions */
Linus Torvalds's avatar
Linus Torvalds committed
908
909
			break;
		case 0x001: /* Invalid Op */
910
911
912
913
914
			/*
			 * swd & 0x240 == 0x040: Stack Underflow
			 * swd & 0x240 == 0x240: Stack Overflow
			 * User must clear the SF bit (0x40) if set
			 */
Linus Torvalds's avatar
Linus Torvalds committed
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
			info.si_code = FPE_FLTINV;
			break;
		case 0x002: /* Denormalize */
		case 0x010: /* Underflow */
			info.si_code = FPE_FLTUND;
			break;
		case 0x004: /* Zero Divide */
			info.si_code = FPE_FLTDIV;
			break;
		case 0x008: /* Overflow */
			info.si_code = FPE_FLTOVF;
			break;
		case 0x020: /* Precision */
			info.si_code = FPE_FLTRES;
			break;
	}
	force_sig_info(SIGFPE, &info, task);
}

fastcall void do_coprocessor_error(struct pt_regs * regs, long error_code)
{
	ignore_fpu_irq = 1;
	math_error((void __user *)regs->eip);
}

static void simd_math_error(void __user *eip)
{
	struct task_struct * task;
	siginfo_t info;
	unsigned short mxcsr;

	/*
	 * Save the info for the exception handler and clear the error.
	 */
	task = current;
	save_init_fpu(task);
	task->thread.trap_no = 19;
	task->thread.error_code = 0;
	info.si_signo = SIGFPE;
	info.si_errno = 0;
	info.si_code = __SI_FAULT;
	info.si_addr = eip;
	/*
	 * The SIMD FPU exceptions are handled a little differently, as there
	 * is only a single status/control register.  Thus, to determine which
	 * unmasked exception was caught we must mask the exception mask bits
	 * at 0x1f80, and then use these to mask the exception bits at 0x3f.
	 */
	mxcsr = get_fpu_mxcsr(task);
	switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
		case 0x000:
		default:
			break;
		case 0x001: /* Invalid Op */
			info.si_code = FPE_FLTINV;
			break;
		case 0x002: /* Denormalize */
		case 0x010: /* Underflow */
			info.si_code = FPE_FLTUND;
			break;
		case 0x004: /* Zero Divide */
			info.si_code = FPE_FLTDIV;
			break;
		case 0x008: /* Overflow */
			info.si_code = FPE_FLTOVF;
			break;
		case 0x020: /* Precision */
			info.si_code = FPE_FLTRES;
			break;
	}
	force_sig_info(SIGFPE, &info, task);
}

fastcall void do_simd_coprocessor_error(struct pt_regs * regs,
					  long error_code)
{
	if (cpu_has_xmm) {
		/* Handle SIMD FPU exceptions on PIII+ processors. */
		ignore_fpu_irq = 1;
		simd_math_error((void __user *)regs->eip);
	} else {
		/*
		 * Handle strange cache flush from user space exception
		 * in all other cases.  This is undocumented behaviour.
		 */
		if (regs->eflags & VM_MASK) {
			handle_vm86_fault((struct kernel_vm86_regs *)regs,
					  error_code);
			return;
		}
		current->thread.trap_no = 19;
		current->thread.error_code = error_code;
1007
		die_if_kernel("cache flush denied", regs, error_code);
Linus Torvalds's avatar
Linus Torvalds committed
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
		force_sig(SIGSEGV, current);
	}
}

fastcall void do_spurious_interrupt_bug(struct pt_regs * regs,
					  long error_code)
{
#if 0
	/* No need to warn about this any longer. */
	printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
#endif
}

Stas Sergeev's avatar
Stas Sergeev committed
1021
1022
fastcall unsigned long patch_espfix_desc(unsigned long uesp,
					  unsigned long kesp)
Linus Torvalds's avatar
Linus Torvalds committed
1023
{
1024
	struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt;
Stas Sergeev's avatar
Stas Sergeev committed
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
	unsigned long base = (kesp - uesp) & -THREAD_SIZE;
	unsigned long new_kesp = kesp - base;
	unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
	__u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS];
	/* Set up base for espfix segment */
 	desc &= 0x00f0ff0000000000ULL;
 	desc |=	((((__u64)base) << 16) & 0x000000ffffff0000ULL) |
		((((__u64)base) << 32) & 0xff00000000000000ULL) |
		((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) |
		(lim_pages & 0xffff);
	*(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc;
	return new_kesp;
Linus Torvalds's avatar
Linus Torvalds committed
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
}

/*
 *  'math_state_restore()' saves the current math information in the
 * old math state array, and gets the new ones from the current task
 *
 * Careful.. There are problems with IBM-designed IRQ13 behaviour.
 * Don't touch unless you *really* know how it works.
 *
 * Must be called with kernel preemption disabled (in this case,
 * local interrupts are disabled at the call-site in entry.S).
 */
1049
asmlinkage void math_state_restore(void)
Linus Torvalds's avatar
Linus Torvalds committed
1050
1051
1052
1053
1054
1055
1056
1057
1058
{
	struct thread_info *thread = current_thread_info();
	struct task_struct *tsk = thread->task;

	clts();		/* Allow maths ops (or we recurse) */
	if (!tsk_used_math(tsk))
		init_fpu(tsk);
	restore_fpu(tsk);
	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
1059
	tsk->fpu_counter++;
Linus Torvalds's avatar
Linus Torvalds committed
1060
1061
1062
1063
1064
1065
}

#ifndef CONFIG_MATH_EMULATION

asmlinkage void math_emulate(long arg)
{
1066
1067
	printk(KERN_EMERG "math-emulation not enabled and no coprocessor found.\n");
	printk(KERN_EMERG "killing %s.\n",current->comm);
Linus Torvalds's avatar
Linus Torvalds committed
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
	force_sig(SIGFPE,current);
	schedule();
}

#endif /* CONFIG_MATH_EMULATION */

#ifdef CONFIG_X86_F00F_BUG
void __init trap_init_f00f_bug(void)
{
	__set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO);

	/*
	 * Update the IDT descriptor and reload the IDT so that
	 * it uses the read-only mapped virtual address.
	 */
	idt_descr.address = fix_to_virt(FIX_F00F_IDT);
1084
	load_idt(&idt_descr);
Linus Torvalds's avatar
Linus Torvalds committed
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
}
#endif

/*
 * This needs to use 'idt_table' rather than 'idt', and
 * thus use the _nonmapped_ version of the IDT, as the
 * Pentium F0 0F bugfix can have resulted in the mapped
 * IDT being write-protected.
 */
void set_intr_gate(unsigned int n, void *addr)
{
1096
	_set_gate(n, DESCTYPE_INT, addr, __KERNEL_CS);
Linus Torvalds's avatar
Linus Torvalds committed
1097
1098
1099
1100
1101
1102
1103
}

/*
 * This routine sets up an interrupt gate at directory privilege level 3.
 */
static inline void set_system_intr_gate(unsigned int n, void *addr)
{
1104
	_set_gate(n, DESCTYPE_INT | DESCTYPE_DPL3, addr, __KERNEL_CS);
Linus Torvalds's avatar
Linus Torvalds committed
1105
1106
1107
1108
}

static void __init set_trap_gate(unsigned int n, void *addr)
{
1109
	_set_gate(n, DESCTYPE_TRAP, addr, __KERNEL_CS);
Linus Torvalds's avatar
Linus Torvalds committed
1110
1111
1112
1113
}

static void __init set_system_gate(unsigned int n, void *addr)
{
1114
	_set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __KERNEL_CS);
Linus Torvalds's avatar
Linus Torvalds committed
1115
1116
1117
1118
}

static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
{
1119
	_set_gate(n, DESCTYPE_TASK, (void *)0, (gdt_entry<<3));
Linus Torvalds's avatar
Linus Torvalds committed
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
}


void __init trap_init(void)
{
#ifdef CONFIG_EISA
	void __iomem *p = ioremap(0x0FFFD9, 4);
	if (readl(p) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) {
		EISA_bus = 1;
	}
	iounmap(p);
#endif

#ifdef CONFIG_X86_LOCAL_APIC
	init_apic_mappings();
#endif

	set_trap_gate(0,&divide_error);
	set_intr_gate(1,&debug);
	set_intr_gate(2,&nmi);
1140
	set_system_intr_gate(3, &int3); /* int3/4 can be called from all */
Linus Torvalds's avatar
Linus Torvalds committed
1141
	set_system_gate(4,&overflow);
1142
	set_trap_gate(5,&bounds);
Linus Torvalds's avatar
Linus Torvalds committed
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
	set_trap_gate(6,&invalid_op);
	set_trap_gate(7,&device_not_available);
	set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS);
	set_trap_gate(9,&coprocessor_segment_overrun);
	set_trap_gate(10,&invalid_TSS);
	set_trap_gate(11,&segment_not_present);
	set_trap_gate(12,&stack_segment);
	set_trap_gate(13,&general_protection);
	set_intr_gate(14,&page_fault);
	set_trap_gate(15,&spurious_interrupt_bug);
	set_trap_gate(16,&coprocessor_error);
	set_trap_gate(17,&alignment_check);
#ifdef CONFIG_X86_MCE
	set_trap_gate(18,&machine_check);
#endif
	set_trap_gate(19,&simd_coprocessor_error);

1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
	if (cpu_has_fxsr) {
		/*
		 * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
		 * Generates a compile-time "error: zero width for bit-field" if
		 * the alignment is wrong.
		 */
		struct fxsrAlignAssert {
			int _:!(offsetof(struct task_struct,
					thread.i387.fxsave) & 15);
		};

		printk(KERN_INFO "Enabling fast FPU save and restore... ");
		set_in_cr4(X86_CR4_OSFXSR);
		printk("done.\n");
	}
	if (cpu_has_xmm) {
		printk(KERN_INFO "Enabling unmasked SIMD FPU exception "
				"support... ");
		set_in_cr4(X86_CR4_OSXMMEXCPT);
		printk("done.\n");
	}

Linus Torvalds's avatar
Linus Torvalds committed
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
	set_system_gate(SYSCALL_VECTOR,&system_call);

	/*
	 * Should be a barrier for any external CPU state.
	 */
	cpu_init();

	trap_init_hook();
}

static int __init kstack_setup(char *s)
{
	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
1195
	return 1;
Linus Torvalds's avatar
Linus Torvalds committed
1196
1197
}
__setup("kstack=", kstack_setup);
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207

static int __init code_bytes_setup(char *s)
{
	code_bytes = simple_strtoul(s, NULL, 0);
	if (code_bytes > 8192)
		code_bytes = 8192;

	return 1;
}
__setup("code_bytes=", code_bytes_setup);