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