]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x64/descriptors.cc
Initial checkin from Perforce.
[polintos/scott/priv.git] / kernel / arch / x64 / descriptors.cc
1 // arch/x64/descriptors.cc -- code to manage segment/trap/interrupt descriptors
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 <arch/addrs.h>
33 #include <arch/thread.h>
34 #include <arch/mem.h>
35
36 namespace Arch {
37 namespace Priv {
38         TSS tss;
39 }
40 }
41
42 using Arch::Priv::Descriptor;
43 using Arch::Priv::TSS;
44 using Arch::Priv::tss;
45
46 Descriptor x64_gdt[1024] = {
47         {}, // The first entry is reserved for the NULL selector.
48         {   // 0x08: data
49                 limit_low: 0xffff,
50                 base_low: 0,
51                 base_mid: 0,
52                 type: 2, // data segment, writable
53                 user: 1,
54                 dpl: 0,
55                 present: 1,
56                 limit_high: 0xff,
57                 sw: 0,
58                 code64: 0,
59                 opsize: 1,
60                 gran: 1,
61                 base_high: 0
62         },
63         {   // 0x10: 32-bit code
64                 limit_low: 0xffff,
65                 base_low: 0,
66                 base_mid: 0,
67                 type: 10, // code segment, readable
68                 user: 1,
69                 dpl: 0,
70                 present: 1,
71                 limit_high: 0xff,
72                 sw: 0,
73                 code64: 0,
74                 opsize: 1,
75                 gran: 1,
76                 base_high: 0
77         },
78         {   // 0x18: 64-bit code
79                 limit_low: 0xffff,
80                 base_low: 0,
81                 base_mid: 0,
82                 type: 10, // code segment, readable
83                 user: 1,
84                 dpl: 0,
85                 present: 1,
86                 limit_high: 0xff,
87                 sw: 0,
88                 code64: 1,
89                 opsize: 0,
90                 gran: 1,
91                 base_high: 0
92         },
93         {   // 0x20: TSS
94                 limit_low: sizeof(TSS) - 4,
95                 base_low: 0,
96                 base_mid: 0,
97                 type: 9,
98                 user: 0,
99                 dpl: 0,
100                 present: 1,
101                 limit_high: 0,
102                 sw: 0,
103                 code64: 0,
104                 opsize: 0,
105                 gran: 0,
106                 base_high: 0,
107         },
108         {   // 0x28: TSS high
109         }
110 };
111
112 struct X64DescriptorTablePointer {
113         u8 pad[6];
114         u16 limit;
115         u64 address;
116 };
117
118 X64DescriptorTablePointer x64_gdtr = {
119         // G++ still won't handle complex labelled initializers, so
120         // we have to explicitly initialize pad.
121         
122         pad: { 0, 0, 0, 0, 0, 0 }, 
123         limit: sizeof(x64_gdt),
124         address: reinterpret_cast<u64>(&x64_gdt)
125 };
126
127 X64DescriptorTablePointer x64_gdtr_phys = {
128         pad: { 0, 0, 0, 0, 0, 0 }, 
129         limit: sizeof(x64_gdt),
130         address: reinterpret_cast<u64>(&x64_gdt) - KERNEL_START
131 };
132
133 struct X64InterruptDescriptor {
134         u16 offset_low;
135         u16 selector;
136         u8 stack_index:3;
137         u8 reserved:5;
138         u8 type:4;
139         u8 user:1;
140         u8 dpl:2;
141         u8 present:1;
142         u16 offset_mid;
143         u32 offset_high;
144         u32 reserved2;
145 };
146         
147 static X64InterruptDescriptor idt[256];
148
149 static X64DescriptorTablePointer idtr = {
150         pad: { 0, 0, 0, 0, 0, 0 }, 
151         limit: sizeof(idt),
152         address: reinterpret_cast<u64>(&idt)
153 };
154
155 // Set a gate for INT num to start executing at addr.  
156 //
157 // If ints_off is set, then interrupts will remain disabled until
158 // software enables them; otherwise, the interrupt flag will have the
159 // same state as in the code that was interrupted.
160 //
161 // If user is true, then this gate can be called directly from
162 // userspace with the INT instruction.  Otherwise, usermode
163 // INT to this gate will cause a GPF, but it may still be reached
164 // from user code via hardware interrupt or exception.
165 // 
166 // If stack_index is non-zero, use the specified alternate stack even if
167 // interrupting kernel code.
168
169 static void set_int_gate(int num, void *addrptr, bool ints_off = false,
170                          bool user = false, int stack_index = 0)
171 {
172         u64 addr = (u64)addrptr;
173
174         X64InterruptDescriptor desc = {
175                 offset_low: addr & 0xffff,
176                 selector: 0x18,
177                 stack_index: stack_index,
178                 reserved: 0,
179                 type: ints_off ? 14 : 15,
180                 user: 0,
181                 dpl: user ? 3 : 0,
182                 present: 1,
183                 offset_mid: (addr >> 16) & 0xffff,
184                 offset_high: addr >> 32
185         };
186         
187         idt[num] = desc;
188 }
189
190 extern int x64_diverr, x64_gpf, x64_page_fault, x64_invalid_insn;
191 extern void *x64_irqs[256];
192
193 namespace Arch {
194 namespace Priv {
195         void set_idt()
196         {
197                 // GCC 4.0 pukes on "m" (&idtr.limit), saying it's not
198                 // directly addressable.
199                 
200                 asm volatile("lidtq 6(%0)" : : "r" (&idtr) : "memory");
201                 
202                 set_int_gate(0, &x64_diverr);
203                 set_int_gate(6, &x64_invalid_insn);
204                 set_int_gate(13, &x64_gpf);
205                 set_int_gate(14, &x64_page_fault, true);
206                 
207                 for (int i = 0x20; i < 0x30; i++)
208                         set_int_gate(i, x64_irqs[i]);
209         }
210 }
211 }