]>
Commit | Line | Data |
---|---|---|
1 | /* traps.c | |
2 | * Trap handling routines | |
3 | * NetWatch system management mode administration console | |
4 | * | |
5 | * Copyright (c) 2008 Jacob Potter and Joshua Wise. All rights reserved. | |
6 | * This program is free software; you can redistribute and/or modify it under | |
7 | * the terms found in the file LICENSE in the root of this source tree. | |
8 | * | |
9 | */ | |
10 | ||
11 | #include <output.h> | |
12 | #include <io.h> | |
13 | #include <paging.h> | |
14 | ||
15 | #include "traps.h" | |
16 | ||
17 | #define CS_SEGSEL 0x8 | |
18 | ||
19 | #define FAULT_WRAPPER(func_name) asm ( \ | |
20 | ".global " #func_name "_wrapper\n" \ | |
21 | #func_name "_wrapper:\n" \ | |
22 | "mov %cr2, %eax\n" \ | |
23 | "push %eax\n" \ | |
24 | "push %esp\n" \ | |
25 | "call " #func_name "\n" \ | |
26 | ); void func_name##_wrapper(void); | |
27 | ||
28 | #define WRAPPER_INSTALL(idt, idt4_value, func_name, int_number) { \ | |
29 | *(int *)((void *)idt + (8 * int_number)) = \ | |
30 | ((int)func_name##_wrapper & 0xFFFF) | \ | |
31 | (CS_SEGSEL << 16); \ | |
32 | *(int *)((void *)idt + (8 * int_number) + 4) = \ | |
33 | ((int)func_name##_wrapper & 0xFFFF0000) | idt4_value; \ | |
34 | } | |
35 | ||
36 | /* The 16 bits at offset 4 from the start of an interrupt gate are a | |
37 | * bitfield, according to the Intel spec: | |
38 | * 15 P - Segment Present - set to 1 | |
39 | * 14-13 DPL - Descriptor privilege level - set to 11 for trap/int, 00 for IPI | |
40 | * 12-8 01111 for 32-bit trap gates, 01110 for 32-bit interrupt gates | |
41 | * 7-0 Set to 0 | |
42 | * Trap: binary 11101111 0000000, hex EF00. | |
43 | * Interrupt: binary 11101110 0000000, hex EE00. | |
44 | */ | |
45 | #define TRAP 0xEF00 | |
46 | #define INTERRUPT 0xEE00 | |
47 | ||
48 | typedef struct trap_t { | |
49 | int cr2; | |
50 | int error_code; | |
51 | int eip; | |
52 | int cs; | |
53 | int eflags; | |
54 | int esp; | |
55 | int ss; | |
56 | } trap_t; | |
57 | ||
58 | void die(struct trap_t * trap) { | |
59 | outputf("Error %08x %%eip %08x", trap->error_code, trap->eip); | |
60 | outputf("%%esp %08x %%eflags %08x", trap->esp, trap->eflags); | |
61 | while(1) asm("hlt"); | |
62 | } | |
63 | ||
64 | void fault_gp(struct trap_t * trap) { | |
65 | outputf("GENERAL PROTECTION FAULT"); | |
66 | die(trap); | |
67 | } | |
68 | ||
69 | void fault_page(struct trap_t * trap) { | |
70 | outputf("PAGE FAULT: %08x", trap->cr2); | |
71 | die(trap); | |
72 | } | |
73 | void fault_divide(struct trap_t * trap) { | |
74 | outputf("DIVISION FAULT"); | |
75 | die(trap); | |
76 | } | |
77 | void double_fault(struct trap_t * trap) { | |
78 | outputf("DOUBLE FAULT"); | |
79 | die(trap); | |
80 | } | |
81 | ||
82 | FAULT_WRAPPER(fault_gp); | |
83 | FAULT_WRAPPER(fault_page); | |
84 | FAULT_WRAPPER(fault_divide); | |
85 | FAULT_WRAPPER(double_fault); | |
86 | ||
87 | /* pseudo_descriptor and x86_gate structs from 15-410 basis code. */ | |
88 | ||
89 | struct x86_gate { | |
90 | unsigned int filler[2]; //64 bits; or 8 bytes. | |
91 | }; | |
92 | ||
93 | static struct x86_gate idt[64]; | |
94 | ||
95 | struct pseudo_descriptor { | |
96 | short pad; | |
97 | unsigned short limit; | |
98 | unsigned long linear_base; | |
99 | } __attribute__((packed)); | |
100 | ||
101 | void traps_install(void) { | |
102 | ||
103 | struct pseudo_descriptor pdesc; | |
104 | pdesc.limit = sizeof(idt) - 1; | |
105 | pdesc.linear_base = v2p(&idt); | |
106 | ||
107 | WRAPPER_INSTALL(idt, TRAP, fault_divide, T_DIVIDE_ERROR); | |
108 | WRAPPER_INSTALL(idt, TRAP, fault_gp, T_GENERAL_PROTECTION); | |
109 | WRAPPER_INSTALL(idt, TRAP, fault_page, T_PAGE_FAULT); | |
110 | WRAPPER_INSTALL(idt, TRAP, double_fault, T_DOUBLE_FAULT); | |
111 | ||
112 | outb(0x80, 0xCC); | |
113 | asm volatile("lidt %0" : : "m" (pdesc.limit)); | |
114 | outb(0x80, 0xCD); | |
115 | } |