]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x86/misc.cc
a1b6e18b2dc2fb5d2171a05ac8fb9eac1da7bc6f
[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 X86InitStack {
32         u8 stack[4096 - ::Threads::thread_size];
33         ::Threads::Thread thread;
34 } __attribute__((aligned(4096))) x86_init_stack;
35
36 namespace Arch {
37         namespace Priv {
38                 void set_idt();
39                 
40                 void show_regs(Regs *regs)
41                 {
42                         printf("eax: 0x%08x   ecx: 0x%08x   edx: 0x%08x   ebx: 0x%08x\n"
43                                "esp: 0x%08x   ebp: 0x%08x   esi: 0x%08x   edi: 0x%08x\n"
44                                "eflags: 0x%08x ds: %04x es: %04x ss: %04x\n",
45                                regs->eax, regs->ecx, regs->edx, regs->ebx,
46                                regs->cs & 3 ? regs->user_esp : (u32)regs + (u32)sizeof(regs),
47                                regs->ebp, regs->esi, regs->edi, regs->eflags,
48                                regs->ds, regs->es, regs->cs & 3 ? regs->user_ss : regs->ds);
49                         
50                         printf("Stack trace:          ");
51                         u32 *frame = (u32 *)regs->ebp;
52                         
53                         for (int i = 2; i < 32; i++) {
54                                 u32 stackptr = frame[1];
55                                 frame = (u32 *)frame[0];
56                                 
57                                 if ((u32)frame < 0x80000000UL)
58                                         break;
59
60                                 if (!(i % 7))
61                                         printf("\n");
62                                 
63                                 printf("0x%08x ", stackptr);
64                         }
65                 }
66
67                 struct TimerInt : public IRQ::Interrupt {
68                         bool action()
69                         {
70                                 Time::monotonic_timers->run();
71                                 return true;
72                         }
73                 };
74                 
75                 TimerInt timer_int;
76         }
77
78         using IRQ::i8259;
79         ::Threads::Thread *init_thread;
80         
81         void arch_init()
82         {
83                 init_thread = &x86_init_stack.thread;
84                 Priv::early_adjust_mappings();
85                 Priv::set_idt();
86                 Priv::MultiBoot::process_info();
87                 i8259.init();
88                 
89                 u32 tss_addr = reinterpret_cast<u32>(&Priv::tss);
90                 x86_gdt[3].base_low = tss_addr & 0xffff;
91                 x86_gdt[3].base_mid = (tss_addr & 0xff0000) >> 16;
92                 x86_gdt[3].base_high = (tss_addr & 0xff000000) >> 24;
93                 
94                 Priv::tss.ss0 = 8;
95                 asm volatile("ltr %w0" : : "r" (0x18) : "memory");
96                 init_thread->addr_space = new Mem::ProcAddrSpace(x86_init_ptbl_l2);
97                 init_thread->active_addr_space = init_thread->addr_space;
98         }
99
100         void timer_init()
101         {
102                 IRQ::InterruptSlot *timer = i8259.get_slot(0);
103                 i8259.request_int(timer, &Priv::timer_int);
104         }
105
106         void ArchThread::init(void *entry, void *arg)
107         {
108                 void **stack = reinterpret_cast<void **>(this);
109                 
110                 *--stack = arg;
111                 *--stack = entry;
112                 
113                 esp = stack;
114                 ebp = 0;
115                 jump_to_init = 1;
116         }
117 }
118
119 using Arch::Priv::show_regs;
120 using Arch::Priv::Regs;
121
122 extern "C" void x86_do_diverr(Regs *regs)
123 {
124         printf("Division error at 0x%04x:0x%08x\n", regs->cs, regs->eip);
125         show_regs(regs);
126         for(;;);
127 }
128
129 extern "C" void x86_do_debug(Regs *regs)
130 {
131         printf("Debug exception at 0x%04x:0x%08x\n", regs->cs, regs->eip);
132         show_regs(regs);
133         for(;;);
134 }
135
136 extern "C" void x86_do_breakpoint(Regs *regs)
137 {
138         printf("Breakpoint at 0x%04x:0x%08x\n", regs->cs, regs->eip);
139         show_regs(regs);
140         for(;;);
141 }
142
143 extern "C" void x86_do_invalid_insn(Regs *regs)
144 {
145         printf("Invalid instruction at 0x%04x:0x%08x\n", regs->cs, regs->eip);
146         show_regs(regs);
147         for(;;);
148 }
149
150 extern "C" void x86_do_page_fault(Regs *regs, 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 (!(regs->eflags & 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                regs->cs, regs->eip, fault_addr, error_code);
193         
194         show_regs(regs);
195
196         for(;;);
197 }
198
199 extern "C" void x86_do_gpf(Regs *regs, 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                regs->cs, regs->eip, error_code);
208
209         show_regs(regs);
210         
211         for(;;);
212 }
213
214 extern "C" void x86_do_irq(int irq)
215 {
216         IRQ::i8259.handle_irq(irq - 0x20);
217 }
218
219 namespace Arch {
220 namespace Priv {
221         struct OrbRegs {
222                 union {
223                         System::RunTime::ParamInfoBlock *pib;
224                         ulong exptr;
225                 };
226                 
227                 union {
228                         ulong caller;
229                         ulong exlen;
230                 };
231                 
232                 ulong eip, cs, eflags, user_esp, user_ss;
233         };
234 }}
235
236 extern "C" void x86_invoke_method(Arch::Priv::OrbRegs *regs)
237 {
238         assert(regs->cs & 3);
239         ORB::invoke_method(regs->pib, regs->user_esp);
240 }
241
242 extern "C" void x86_return_from_method(Arch::Priv::OrbRegs *regs)
243 {
244         assert(regs->cs & 3);
245         regs->user_esp = ORB::return_from_method(regs->exptr, regs->exlen);
246 }