1 // arch/x86/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 condition:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
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
23 #include <kern/types.h>
24 #include <arch/addrs.h>
25 #include <arch/thread.h>
34 using Arch::Priv::Descriptor;
35 using Arch::Priv::TSS;
36 using Arch::Priv::tss;
38 Descriptor x86_gdt[1024] = {
39 {}, // The first entry is reserved for the NULL selector.
44 type: 2, // data segment, writable
59 type: 10, // code segment, readable
71 limit_low: sizeof(tss),
87 struct X86DescriptorTablePointer {
93 X86DescriptorTablePointer x86_gdtr = {
94 // G++ still won't handle complex labelled initializers, so
95 // we have to explicitly initialize pad.
97 pad: { 0, 0, 0, 0, 0, 0 },
98 limit: sizeof(x86_gdt),
99 address: reinterpret_cast<u32>(&x86_gdt)
102 X86DescriptorTablePointer x86_gdtr_phys = {
103 pad: { 0, 0, 0, 0, 0, 0 },
104 limit: sizeof(x86_gdt),
105 address: reinterpret_cast<u32>(&x86_gdt) - KERNEL_START
108 struct X86InterruptDescriptor {
120 static X86InterruptDescriptor idt[256];
122 static X86DescriptorTablePointer idtr = {
123 pad: { 0, 0, 0, 0, 0, 0 },
125 address: reinterpret_cast<u32>(&idt)
128 // Set a gate for INT num to start executing at addr.
130 // If ints_off is set, then interrupts will remain disabled until
131 // software enables them; otherwise, the interrupt flag will have the
132 // same state as in the code that was interrupted.
134 // If user is true, then this gate can be called directly from
135 // userspace with the INT instruction. Otherwise, usermode
136 // INT to this gate will cause a GPF, but it may still be reached
137 // from user code via hardware interrupt or exception.
139 // If stack_index is non-zero, use the specified alternate stack even if
140 // interrupting kernel code.
142 static void set_int_gate(int num, void *addrptr, bool ints_off = false,
143 bool user = false, int stack_index = 0)
145 u32 addr = (u32)addrptr;
147 X86InterruptDescriptor desc = {
148 offset_low: addr & 0xffff,
150 stack_index: stack_index,
152 type: ints_off ? 14 : 15,
156 offset_high: (addr >> 16) & 0xffff,
162 extern int x86_diverr, x86_debug, x86_breakpoint;
163 extern int x86_gpf, x86_page_fault, x86_invalid_insn, x86_int99_entry;
164 extern void *x86_irqs[256];
170 // GCC 4.0 pukes on "m" (&idtr.limit), saying it's not
171 // directly addressable.
173 asm volatile("lidtl 6(%0)" : : "r" (&idtr) : "memory");
175 set_int_gate(0, &x86_diverr);
176 set_int_gate(1, &x86_debug);
177 set_int_gate(3, &x86_breakpoint);
178 set_int_gate(6, &x86_invalid_insn);
179 set_int_gate(13, &x86_gpf);
180 set_int_gate(14, &x86_page_fault, true);
181 set_int_gate(0x99, &x86_int99_entry);
183 for (int i = 0x20; i < 0x30; i++)
184 set_int_gate(i, x86_irqs[i], true);