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