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 // 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.
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.
15 #include <kern/types.h>
16 #include <arch/addrs.h>
17 #include <arch/thread.h>
26 using Arch::Priv::Descriptor;
27 using Arch::Priv::TSS;
28 using Arch::Priv::tss;
30 Descriptor x64_gdt[1024] = {
31 {}, // The first entry is reserved for the NULL selector.
36 type: 2, // data segment, writable
47 { // 0x10: 32-bit code
51 type: 10, // code segment, readable
62 { // 0x18: 64-bit code
66 type: 10, // code segment, readable
78 limit_low: sizeof(TSS) - 4,
96 struct X64DescriptorTablePointer {
102 X64DescriptorTablePointer x64_gdtr = {
103 // G++ still won't handle complex labelled initializers, so
104 // we have to explicitly initialize pad.
106 pad: { 0, 0, 0, 0, 0, 0 },
107 limit: sizeof(x64_gdt),
108 address: reinterpret_cast<u64>(&x64_gdt)
111 X64DescriptorTablePointer x64_gdtr_phys = {
112 pad: { 0, 0, 0, 0, 0, 0 },
113 limit: sizeof(x64_gdt),
114 address: reinterpret_cast<u64>(&x64_gdt) - KERNEL_START
117 struct X64InterruptDescriptor {
131 static X64InterruptDescriptor idt[256];
133 static X64DescriptorTablePointer idtr = {
134 pad: { 0, 0, 0, 0, 0, 0 },
136 address: reinterpret_cast<u64>(&idt)
139 // Set a gate for INT num to start executing at addr.
141 // If ints_off is set, then interrupts will remain disabled until
142 // software enables them; otherwise, the interrupt flag will have the
143 // same state as in the code that was interrupted.
145 // If user is true, then this gate can be called directly from
146 // userspace with the INT instruction. Otherwise, usermode
147 // INT to this gate will cause a GPF, but it may still be reached
148 // from user code via hardware interrupt or exception.
150 // If stack_index is non-zero, use the specified alternate stack even if
151 // interrupting kernel code.
153 static void set_int_gate(int num, void *addrptr, bool ints_off = false,
154 bool user = false, int stack_index = 0)
156 u64 addr = (u64)addrptr;
158 X64InterruptDescriptor desc = {
159 offset_low: addr & 0xffff,
161 stack_index: stack_index,
163 type: ints_off ? 14 : 15,
167 offset_mid: (addr >> 16) & 0xffff,
168 offset_high: addr >> 32
174 extern int x64_diverr, x64_gpf, x64_page_fault, x64_invalid_insn;
175 extern void *x64_irqs[256];
181 // GCC 4.0 pukes on "m" (&idtr.limit), saying it's not
182 // directly addressable.
184 asm volatile("lidtq 6(%0)" : : "r" (&idtr) : "memory");
186 set_int_gate(0, &x64_diverr);
187 set_int_gate(6, &x64_invalid_insn);
188 set_int_gate(13, &x64_gpf);
189 set_int_gate(14, &x64_page_fault, true);
191 for (int i = 0x20; i < 0x30; i++)
192 set_int_gate(i, x64_irqs[i]);