]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x86/misc.cc
update
[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 #include <kern/process.h>
23 #include <kern/orb.h>
24
25 #include <arch/addrs.h>
26 #include <arch/multiboot.h>
27 #include <arch/regs.h>
28
29 extern u32 x86_init_ptbl_l2[1024];
30
31 struct X86ExTable {
32         ulong faultaddr, handler;
33 };
34
35 extern X86ExTable extable_start, extable_end;
36
37 struct X86InitStack {
38         u8 stack[4096 - ::Threads::thread_size];
39         ::Threads::Thread thread;
40 } __attribute__((aligned(4096))) x86_init_stack;
41
42 namespace Arch {
43         namespace Priv {
44                 void set_idt();
45                 
46                 void show_regs(Regs *regs)
47                 {
48                         u32 esp = regs->cs & 3 ? regs->user_esp :
49                                   (u32)regs + (u32)sizeof(regs);
50
51                         printf("eax: 0x%08x   ecx: 0x%08x   edx: 0x%08x   ebx: 0x%08x\n"
52                                "esp: 0x%08x   ebp: 0x%08x   esi: 0x%08x   edi: 0x%08x\n"
53                                "eflags: 0x%08x ds: %04x es: %04x ss: %04x\n",
54                                regs->eax, regs->ecx, regs->edx, regs->ebx, esp,
55                                regs->ebp, regs->esi, regs->edi, regs->eflags,
56                                regs->ds, regs->es, regs->cs & 3 ? regs->user_ss : regs->ds);
57
58                         printf("Stack trace:          ");
59                         u32 *frame = (u32 *)regs->ebp;
60                         
61                         for (int i = 2; i < 32; i++) {
62                                 if ((u32)frame < 0x80000000UL)
63                                         break;
64
65                                 u32 stackptr = frame[1];
66                                 frame = (u32 *)frame[0];
67
68                                 if (!(i % 7))
69                                         printf("\n");
70                                 
71                                 printf("0x%08x ", stackptr);
72                         }
73
74                         printf("\nStack dump:           ");
75
76                         for (int i = 2; i < 32; i++) {
77                                 if (!(i % 7))
78                                         printf("\n");
79                                 
80                                 printf("0x%08x ", ((u32 *)esp)[i-2]);
81                         }
82                         
83                 }
84
85                 struct TimerInt : public IRQ::Interrupt {
86                         bool action()
87                         {
88                                 Time::monotonic_timers->run();
89                                 return true;
90                         }
91                 };
92                 
93                 TimerInt timer_int;
94                 
95                 bool check_extable(Regs *regs, int cause)
96                 {
97                         X86ExTable *ext;
98                         assert((regs->cs & 3) == 0);
99                         
100                         for (ext = &extable_start; ext < &extable_end; ext++) {
101                                 if (ext->faultaddr == regs->eip) {
102                                         regs->eip = ext->handler;
103                                         regs->edx = cause;
104                                         return true;
105                                 }
106                         }
107                 
108                         return false;
109                 }
110         }
111
112         using IRQ::i8259;
113         ::Threads::Thread *init_thread;
114         
115         void arch_init()
116         {
117                 init_thread = &x86_init_stack.thread;
118                 Priv::early_adjust_mappings();
119                 Priv::set_idt();
120                 Priv::MultiBoot::process_info();
121                 i8259.init();
122                 
123                 u32 tss_addr = reinterpret_cast<u32>(&Priv::tss);
124                 x86_gdt[3].base_low = tss_addr & 0xffff;
125                 x86_gdt[3].base_mid = (tss_addr & 0xff0000) >> 16;
126                 x86_gdt[3].base_high = (tss_addr & 0xff000000) >> 24;
127                 
128                 Priv::tss.ss0 = 8;
129                 asm volatile("ltr %w0" : : "r" (0x18) : "memory");
130                 init_thread->aspace = new Mem::ProcAddrSpace(x86_init_ptbl_l2);
131                 init_thread->active_aspace = init_thread->aspace;
132         }
133
134         void timer_init()
135         {
136                 IRQ::InterruptSlot *timer = i8259.get_slot(0);
137                 i8259.request_int(timer, &Priv::timer_int);
138         }
139 }
140
141 using Arch::Priv::show_regs;
142 using Arch::Priv::Regs;
143
144 extern "C" void x86_do_diverr(Regs *regs)
145 {
146         printf("Division error at 0x%04x:0x%08x\n", regs->cs, regs->eip);
147         show_regs(regs);
148         for(;;);
149 }
150
151 extern "C" void x86_do_debug(Regs *regs)
152 {
153         printf("Debug exception at 0x%04x:0x%08x\n", regs->cs, regs->eip);
154         show_regs(regs);
155         for(;;);
156 }
157
158 extern "C" void x86_do_breakpoint(Regs *regs)
159 {
160         printf("Breakpoint at 0x%04x:0x%08x\n", regs->cs, regs->eip);
161         show_regs(regs);
162         for(;;);
163 }
164
165 extern "C" void x86_do_invalid_insn(Regs *regs)
166 {
167         printf("Invalid instruction at 0x%04x:0x%08x\n", regs->cs, regs->eip);
168         show_regs(regs);
169         for(;;);
170 }
171
172 extern "C" void x86_do_page_fault(Regs *regs, u32 fault_addr, u32 error_code)
173 {
174         Mem::AddrSpace *as;
175         int cause;
176
177         if (in_fault)
178                 for(;;);
179
180         // A reserved bit was set in the PTE; this is always a bug.
181         if (error_code & 8)
182                 goto bad_fault;
183         
184         // Don't try to fix up a page fault if interrupts were disabled.  It is an
185         // error to access non-locked pages with interrupts disabled.  Trying to
186         // fix it up in the case of an access that would be legitimate if interrupts
187         // were enabled would simply mask the loss of atomicity, and trying to grab
188         // locks to look up the address if it is a completely bad reference won't
189         // accomplish much other than decreasing the odds that the fault message
190         // gets out.
191         
192         if (!(regs->eflags & 0x200))
193                 goto bad_fault;
194         
195         // Don't allow fault-ins using a borrowed addr-space.
196         as = curthread->aspace;
197
198         if (!as || curthread == Arch::init_thread)
199                 goto bad_fault;
200         
201         ll_ints_on();
202         
203         // FIXME: no-exec
204         cause = as->handle_fault(fault_addr, error_code & 2,
205                                  false /* error_code & 16 */,
206                                  error_code & 4);
207         
208         if (cause < 0)
209                 return;
210         
211         if (!(error_code & 4) && check_extable(regs, cause))
212                 return;
213         
214         // FIXME: throw exception to user
215
216 bad_fault:
217         ll_ints_off();
218         in_fault++;
219         
220         printf("Page fault at 0x%04x:0x%08x for 0x%08x, error code: 0x%04x\n",
221                regs->cs, regs->eip, fault_addr, error_code);
222         
223         show_regs(regs);
224
225         for(;;);
226 }
227
228 extern "C" void x86_do_gpf(Regs *regs, u32 error_code)
229 {
230         if (in_fault)
231                 for(;;);
232         
233         in_fault++;
234
235         printf("General protection fault at 0x%04x:0x%08x, error code: 0x%04x\n",
236                regs->cs, regs->eip, error_code);
237
238         show_regs(regs);
239         
240         for(;;);
241 }
242
243 extern "C" void x86_do_irq(int irq)
244 {
245         IRQ::i8259.handle_irq(irq - 0x20);
246 }
247
248 namespace Arch {
249 namespace Priv {
250         struct OrbRegs {
251                 u32 ds, es;
252         
253                 union {
254                         System::RunTime::ParamInfoBlock *pib;
255                         ulong exptr;
256                 };
257                 
258                 union {
259                         ulong caller;
260                         ulong exlen;
261                 };
262                 
263                 ulong eip, cs, eflags, user_esp, user_ss;
264         };
265 }}
266
267 extern "C" void x86_invoke_method(Arch::Priv::OrbRegs *regs)
268 {
269         assert(regs->cs & 3);
270         printf("x86_invoke_method %p\n", regs->pib);
271         
272         try {
273                 ORB::invoke_method(regs->pib, regs->user_esp);
274         }
275         
276         catch (SystemException &se) {
277                 // Copy exception to user
278                 // If an exception is thrown during dispatch, it must be
279                 // with the caller's address space, and user_esp must be
280                 // the caller's.
281                 
282                 printf("sys exception\n");
283                 
284                 typedef System::Exceptions::NativeCodeExceptionOriginInfo OriginInfo;
285                 OriginInfo *oi = OriginInfo::downcast(se.origin);
286         
287                 if (oi)
288                         printf("PC %llx\n", oi->pc);
289         }
290         
291         catch (...) {
292                 printf("other exception\n");
293         }
294 }
295
296 extern "C" void x86_return_from_method(Arch::Priv::OrbRegs *regs)
297 {
298         assert(regs->cs & 3);
299         regs->user_esp = ORB::return_from_method(regs->exptr, regs->exlen);
300 }