bb01a1622f2b0cabcdfa4ed0f5c5aaed87baea5c
[polintos/scott/priv.git] / kernel / arch / x86 / misc.cc
1 // arch/x86/misc.cc -- Misc. arch-specific stuff
2 //
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
4 // 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following conditions:
11 // 
12 //     * Redistributions of source code must retain the above copyright notice,
13 //       this list of conditions and the following disclaimers.
14 // 
15 //     * Redistributions in binary form must reproduce the above copyright notice,
16 //       this list of conditions and the following disclaimers in the
17 //       documentation and/or other materials provided with the distribution.
18 // 
19 //     * The names of the Software's authors and/or contributors
20 //       may not be used to endorse or promote products derived from
21 //       this Software without specific prior written permission.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
25 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
29 // SOFTWARE.
30
31 #include <kern/types.h>
32 #include <kern/libc.h>
33 #include <kern/arch.h>
34 #include <kern/i8259.h>
35 #include <kern/time.h>
36 #include <kern/thread.h>
37 #include <kern/mem.h>
38
39 #include <arch/addrs.h>
40 #include <arch/multiboot.h>
41
42 extern u32 x86_init_ptbl_l2[1024];
43
44 struct X86InitStack {
45         u8 stack[4096 - ::Threads::thread_size];
46         ::Threads::Thread thread;
47 } __attribute__((aligned(4096))) x86_init_stack;
48
49 namespace Arch {
50         namespace Priv {
51                 void set_idt();
52                 
53                 void show_regs(u32 *stack) {
54                         printf("eax: 0x%08x   ecx: 0x%08x   edx: 0x%08x   ebx: 0x%08x\n"
55                                "esp: 0x%08x   ebp: 0x%08x   esi: 0x%08x   edi: 0x%08x\n"
56                                "eflags: 0x%08x\n",
57                                stack[0],
58                                stack[1],
59                                stack[2],
60                                stack[3],
61                                stack[9] & 3 ? stack[11] : (u32)stack + 11 * 4,
62                                stack[5],
63                                stack[6],
64                                stack[7],
65                                stack[10]);
66                         
67                         printf("Stack trace:          ");
68                         u32 *frame = (u32 *)stack[5];
69                         
70                         for (int i = 2; i < 32; i++) {
71                                 u32 stackptr = frame[1];
72                                 frame = (u32 *)frame[0];
73                                 
74                                 if ((u32)frame < 0x80000000UL)
75                                         break;
76
77                                 if (!(i % 7))
78                                         printf("\n");
79                                 
80                                 printf("0x%08x ", stackptr);
81                         }
82                 }
83
84                 struct TimerInt : public IRQ::Interrupt {
85                         bool action()
86                         {
87                                 Time::monotonic_timers->run();
88                                 return true;
89                         }
90                 };
91                 
92                 TimerInt timer_int;
93         }
94
95         using IRQ::i8259;
96         ::Threads::Thread *init_thread;
97         
98         void arch_init()
99         {
100                 init_thread = &x86_init_stack.thread;
101                 Priv::early_adjust_mappings();
102                 Priv::set_idt();
103                 Priv::MultiBoot::process_info();
104                 i8259.init();
105                 
106                 u32 tss_addr = reinterpret_cast<u32>(&Priv::tss);
107                 x86_gdt[3].base_low = tss_addr & 0xffff;
108                 x86_gdt[3].base_mid = (tss_addr & 0xff0000) >> 16;
109                 x86_gdt[3].base_high = (tss_addr & 0xff000000) >> 24;
110                 
111                 Priv::tss.ss0 = 8;
112                 asm volatile("ltr %w0" : : "r" (0x18) : "memory");
113                 init_thread->addr_space = new Mem::AddrSpace(x86_init_ptbl_l2);
114                 init_thread->active_addr_space = init_thread->addr_space;
115         }
116
117         void timer_init()
118         {
119                 IRQ::InterruptSlot *timer = i8259.get_slot(0);
120                 i8259.request_int(timer, &Priv::timer_int);
121         }
122
123         void ArchThread::init(void *entry, void *arg)
124         {
125                 void **stack = reinterpret_cast<void **>(this);
126                 
127                 *--stack = arg;
128                 *--stack = entry;
129                 
130                 esp = stack;
131                 ebp = 0;
132                 jump_to_init = 1;
133         }
134 }
135
136 using Arch::Priv::show_regs;
137
138 extern "C" void x86_do_diverr(u32 *stack)
139 {
140         printf("Division error at 0x%04x:0x%08x\n", stack[9], stack[8]);
141         show_regs(stack);
142         for(;;);
143 }
144
145 extern "C" void x86_do_debug(u32 *stack)
146 {
147         printf("Debug exception at 0x%04x:0x%08x\n", stack[9], stack[8]);
148         show_regs(stack);
149         for(;;);
150 }
151
152 extern "C" void x86_do_breakpoint(u32 *stack)
153 {
154         printf("Breakpoint at 0x%04x:0x%08x\n", stack[9], stack[8]);
155         show_regs(stack);
156         for(;;);
157 }
158
159 extern "C" void x86_do_invalid_insn(u32 *stack)
160 {
161         printf("Invalid instruction at 0x%04x:0x%08x\n", stack[9], stack[8]);
162         show_regs(stack);
163         for(;;);
164 }
165
166 extern "C" void x86_do_page_fault(u32 *stack, u32 fault_addr, u32 error_code)
167 {
168         Mem::AddrSpace *as;
169
170         if (in_fault)
171                 for(;;);
172
173         // A reserved bit was set in the PTE; this is always a bug.
174         if (error_code & 8)
175                 goto bad_fault;
176         
177         // Don't try to fix up a page fault if interrupts were disabled.  It is an
178         // error to access non-locked pages with interrupts disabled.  Trying to
179         // fix it up in the case of an access that would be legitimate if interrupts
180         // were enabled would simply mask the loss of atomicity, and trying to grab
181         // locks to look up the address if it is a completely bad reference won't
182         // accomplish much other than decreasing the odds that the fault message
183         // gets out.
184         
185         if (!(stack[10] & 0x200))
186                 goto bad_fault;
187         
188         // Don't allow fault-ins using a borrowed addr-space.
189         as = curthread->addr_space;
190
191         if (!as || curthread == Arch::init_thread)
192                 goto bad_fault;
193         
194         ll_ints_on();
195         
196         // FIXME: no-exec
197         if (as->handle_fault(fault_addr, error_code & 2,
198                              false /* error_code & 16 */, error_code & 4))
199                 return;
200         
201         // FIXME: throw exception to user
202
203 bad_fault:
204         ll_ints_off();
205         in_fault++;
206         
207         printf("Page fault at 0x%04x:0x%08x for 0x%08x, error code: 0x%04x\n",
208                stack[9], stack[8], fault_addr, error_code);
209         
210         show_regs(stack);
211
212         for(;;);
213 }
214
215 extern "C" void x86_do_gpf(u32 *stack, u32 error_code)
216 {
217         if (in_fault)
218                 for(;;);
219         
220         in_fault++;
221
222         printf("General protection fault at 0x%04x:0x%08x, error code: 0x%04x\n",
223                stack[9], stack[8], error_code);
224
225         show_regs(stack);
226         
227         for(;;);
228 }
229
230 extern "C" void x86_do_irq(int irq)
231 {
232         IRQ::i8259.handle_irq(irq - 0x20);
233 }