1 // arch/x64/descriptors.cc -- code to manage segment/trap/interrupt descriptors
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
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:
12 // * Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimers.
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.
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.
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
31 #include <kern/types.h>
32 #include <arch/addrs.h>
33 #include <arch/thread.h>
42 using Arch::Priv::Descriptor;
43 using Arch::Priv::TSS;
44 using Arch::Priv::tss;
46 Descriptor x64_gdt[1024] = {
47 {}, // The first entry is reserved for the NULL selector.
52 type: 2, // data segment, writable
63 { // 0x10: 32-bit code
67 type: 10, // code segment, readable
78 { // 0x18: 64-bit code
82 type: 10, // code segment, readable
94 limit_low: sizeof(TSS) - 4,
112 struct X64DescriptorTablePointer {
118 X64DescriptorTablePointer x64_gdtr = {
119 // G++ still won't handle complex labelled initializers, so
120 // we have to explicitly initialize pad.
122 pad: { 0, 0, 0, 0, 0, 0 },
123 limit: sizeof(x64_gdt),
124 address: reinterpret_cast<u64>(&x64_gdt)
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
133 struct X64InterruptDescriptor {
147 static X64InterruptDescriptor idt[256];
149 static X64DescriptorTablePointer idtr = {
150 pad: { 0, 0, 0, 0, 0, 0 },
152 address: reinterpret_cast<u64>(&idt)
155 // Set a gate for INT num to start executing at addr.
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.
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.
166 // If stack_index is non-zero, use the specified alternate stack even if
167 // interrupting kernel code.
169 static void set_int_gate(int num, void *addrptr, bool ints_off = false,
170 bool user = false, int stack_index = 0)
172 u64 addr = (u64)addrptr;
174 X64InterruptDescriptor desc = {
175 offset_low: addr & 0xffff,
177 stack_index: stack_index,
179 type: ints_off ? 14 : 15,
183 offset_mid: (addr >> 16) & 0xffff,
184 offset_high: addr >> 32
190 extern int x64_diverr, x64_gpf, x64_page_fault, x64_invalid_insn;
191 extern void *x64_irqs[256];
197 // GCC 4.0 pukes on "m" (&idtr.limit), saying it's not
198 // directly addressable.
200 asm volatile("lidtq 6(%0)" : : "r" (&idtr) : "memory");
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);
207 for (int i = 0x20; i < 0x30; i++)
208 set_int_gate(i, x64_irqs[i]);