]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x86/misc.cc
Lots of stuff.
[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 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
8 // 
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
14
15 #include <kern/types.h>
16 #include <kern/libc.h>
17 #include <kern/arch.h>
18 #include <kern/i8259.h>
19 #include <kern/time.h>
20 #include <kern/thread.h>
21 #include <kern/mem.h>
22
23 #include <arch/addrs.h>
24 #include <arch/multiboot.h>
25
26 extern u32 x86_init_ptbl_l2[1024];
27
28 struct X86InitStack {
29         u8 stack[4096 - ::Threads::thread_size];
30         ::Threads::Thread thread;
31 } __attribute__((aligned(4096))) x86_init_stack;
32
33 namespace Arch {
34         namespace Priv {
35                 void set_idt();
36                 
37                 void show_regs(u32 *stack) {
38                         printf("eax: 0x%08x   ecx: 0x%08x   edx: 0x%08x   ebx: 0x%08x\n"
39                                "esp: 0x%08x   ebp: 0x%08x   esi: 0x%08x   edi: 0x%08x\n"
40                                "eflags: 0x%08x\n",
41                                stack[0],
42                                stack[1],
43                                stack[2],
44                                stack[3],
45                                stack[9] & 3 ? stack[11] : (u32)stack + 11 * 4,
46                                stack[5],
47                                stack[6],
48                                stack[7],
49                                stack[10]);
50                         
51                         printf("Stack trace:          ");
52                         u32 *frame = (u32 *)stack[5];
53                         
54                         for (int i = 2; i < 32; i++) {
55                                 u32 stackptr = frame[1];
56                                 frame = (u32 *)frame[0];
57                                 
58                                 if ((u32)frame < 0x80000000UL)
59                                         break;
60
61                                 if (!(i % 7))
62                                         printf("\n");
63                                 
64                                 printf("0x%08x ", stackptr);
65                         }
66                 }
67
68                 struct TimerInt : public IRQ::Interrupt {
69                         bool action()
70                         {
71                                 Time::monotonic_timers->run();
72                                 return true;
73                         }
74                 };
75                 
76                 TimerInt timer_int;
77         }
78
79         using IRQ::i8259;
80         ::Threads::Thread *init_thread;
81         
82         void arch_init()
83         {
84                 init_thread = &x86_init_stack.thread;
85                 Priv::early_adjust_mappings();
86                 Priv::set_idt();
87                 Priv::MultiBoot::process_info();
88                 i8259.init();
89                 
90                 u32 tss_addr = reinterpret_cast<u32>(&Priv::tss);
91                 x86_gdt[3].base_low = tss_addr & 0xffff;
92                 x86_gdt[3].base_mid = (tss_addr & 0xff0000) >> 16;
93                 x86_gdt[3].base_high = (tss_addr & 0xff000000) >> 24;
94                 
95                 Priv::tss.ss0 = 8;
96                 asm volatile("ltr %w0" : : "r" (0x18) : "memory");
97                 init_thread->addr_space = new Mem::ProcAddrSpace(x86_init_ptbl_l2);
98                 init_thread->active_addr_space = init_thread->addr_space;
99         }
100
101         void timer_init()
102         {
103                 IRQ::InterruptSlot *timer = i8259.get_slot(0);
104                 i8259.request_int(timer, &Priv::timer_int);
105         }
106
107         void ArchThread::init(void *entry, void *arg)
108         {
109                 void **stack = reinterpret_cast<void **>(this);
110                 
111                 *--stack = arg;
112                 *--stack = entry;
113                 
114                 esp = stack;
115                 ebp = 0;
116                 jump_to_init = 1;
117         }
118 }
119
120 using Arch::Priv::show_regs;
121
122 extern "C" void x86_do_diverr(u32 *stack)
123 {
124         printf("Division error at 0x%04x:0x%08x\n", stack[9], stack[8]);
125         show_regs(stack);
126         for(;;);
127 }
128
129 extern "C" void x86_do_debug(u32 *stack)
130 {
131         printf("Debug exception at 0x%04x:0x%08x\n", stack[9], stack[8]);
132         show_regs(stack);
133         for(;;);
134 }
135
136 extern "C" void x86_do_breakpoint(u32 *stack)
137 {
138         printf("Breakpoint at 0x%04x:0x%08x\n", stack[9], stack[8]);
139         show_regs(stack);
140         for(;;);
141 }
142
143 extern "C" void x86_do_invalid_insn(u32 *stack)
144 {
145         printf("Invalid instruction at 0x%04x:0x%08x\n", stack[9], stack[8]);
146         show_regs(stack);
147         for(;;);
148 }
149
150 extern "C" void x86_do_page_fault(u32 *stack, u32 fault_addr, u32 error_code)
151 {
152         Mem::AddrSpace *as;
153
154         if (in_fault)
155                 for(;;);
156
157         // A reserved bit was set in the PTE; this is always a bug.
158         if (error_code & 8)
159                 goto bad_fault;
160         
161         // Don't try to fix up a page fault if interrupts were disabled.  It is an
162         // error to access non-locked pages with interrupts disabled.  Trying to
163         // fix it up in the case of an access that would be legitimate if interrupts
164         // were enabled would simply mask the loss of atomicity, and trying to grab
165         // locks to look up the address if it is a completely bad reference won't
166         // accomplish much other than decreasing the odds that the fault message
167         // gets out.
168         
169         if (!(stack[10] & 0x200))
170                 goto bad_fault;
171         
172         // Don't allow fault-ins using a borrowed addr-space.
173         as = curthread->addr_space;
174
175         if (!as || curthread == Arch::init_thread)
176                 goto bad_fault;
177         
178         ll_ints_on();
179         
180         // FIXME: no-exec
181         if (as->handle_fault(fault_addr, error_code & 2,
182                              false /* error_code & 16 */, error_code & 4))
183                 return;
184         
185         // FIXME: throw exception to user
186
187 bad_fault:
188         ll_ints_off();
189         in_fault++;
190         
191         printf("Page fault at 0x%04x:0x%08x for 0x%08x, error code: 0x%04x\n",
192                stack[9], stack[8], fault_addr, error_code);
193         
194         show_regs(stack);
195
196         for(;;);
197 }
198
199 extern "C" void x86_do_gpf(u32 *stack, u32 error_code)
200 {
201         if (in_fault)
202                 for(;;);
203         
204         in_fault++;
205
206         printf("General protection fault at 0x%04x:0x%08x, error code: 0x%04x\n",
207                stack[9], stack[8], error_code);
208
209         show_regs(stack);
210         
211         for(;;);
212 }
213
214 extern "C" void x86_do_irq(int irq)
215 {
216         IRQ::i8259.handle_irq(irq - 0x20);
217 }