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