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 // 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 x86_gdt[1024] = {
31 {}, // The first entry is reserved for the NULL selector.
32 { // 0x08: kernel data
36 type: 2, // data segment, writable
47 { // 0x10: kernel code
51 type: 10, // code segment, readable
63 limit_low: sizeof(tss),
81 type: 2, // data segment, writable
96 type: 10, // code segment, readable
109 struct X86DescriptorTablePointer {
115 X86DescriptorTablePointer x86_gdtr = {
116 // G++ still won't handle complex labelled initializers, so
117 // we have to explicitly initialize pad.
119 pad: { 0, 0, 0, 0, 0, 0 },
120 limit: sizeof(x86_gdt),
121 address: reinterpret_cast<u32>(&x86_gdt)
124 X86DescriptorTablePointer x86_gdtr_phys = {
125 pad: { 0, 0, 0, 0, 0, 0 },
126 limit: sizeof(x86_gdt),
127 address: reinterpret_cast<u32>(&x86_gdt) - KERNEL_START
130 struct X86InterruptDescriptor {
142 static X86InterruptDescriptor idt[256];
144 static X86DescriptorTablePointer idtr = {
145 pad: { 0, 0, 0, 0, 0, 0 },
147 address: reinterpret_cast<u32>(&idt)
150 // Set a gate for INT num to start executing at addr.
152 // If ints_off is set, then interrupts will remain disabled until
153 // software enables them; otherwise, the interrupt flag will have the
154 // same state as in the code that was interrupted.
156 // If user is true, then this gate can be called directly from
157 // userspace with the INT instruction. Otherwise, usermode
158 // INT to this gate will cause a GPF, but it may still be reached
159 // from user code via hardware interrupt or exception.
161 // If stack_index is non-zero, use the specified alternate stack even if
162 // interrupting kernel code.
164 static void set_int_gate(int num, void *addrptr, bool ints_off = false,
165 bool user = false, int stack_index = 0)
167 u32 addr = (u32)addrptr;
169 X86InterruptDescriptor desc = {
170 offset_low: addr & 0xffff,
172 stack_index: stack_index,
174 type: ints_off ? 14 : 15,
178 offset_high: (addr >> 16) & 0xffff,
184 extern int x86_diverr, x86_debug, x86_breakpoint;
185 extern int x86_gpf, x86_page_fault, x86_invalid_insn;
186 extern int x86_int98_entry, x86_int99_entry, x86_int9a_entry, x86_int9b_entry;
187 extern void *x86_irqs[256];
193 // GCC 4.0 pukes on "m" (&idtr.limit), saying it's not
194 // directly addressable.
196 asm volatile("lidtl 6(%0)" : : "r" (&idtr) : "memory");
198 set_int_gate(0, &x86_diverr);
199 set_int_gate(1, &x86_debug);
200 set_int_gate(3, &x86_breakpoint);
201 set_int_gate(6, &x86_invalid_insn);
202 set_int_gate(13, &x86_gpf);
203 set_int_gate(14, &x86_page_fault, true);
204 set_int_gate(0x98, &x86_int98_entry, false, true);
205 set_int_gate(0x99, &x86_int99_entry, false, true);
206 set_int_gate(0x9a, &x86_int9a_entry, false, true);
207 set_int_gate(0x9b, &x86_int9b_entry, false, true);
209 for (int i = 0x20; i < 0x30; i++)
210 set_int_gate(i, x86_irqs[i], true);