]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x86/descriptors.cc
e281895386764fec8f8481a58c5d455bfca38421
[polintos/scott/priv.git] / kernel / arch / x86 / descriptors.cc
1 // arch/x86/descriptors.cc -- code to manage segment/trap/interrupt descriptors
2 //
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
4 // 
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.
8 // 
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.
14
15 #include <kern/types.h>
16 #include <arch/addrs.h>
17 #include <arch/thread.h>
18 #include <arch/mem.h>
19
20 namespace Arch {
21 namespace Priv {
22         TSS tss;
23 }
24 }
25
26 using Arch::Priv::Descriptor;
27 using Arch::Priv::TSS;
28 using Arch::Priv::tss;
29
30 Descriptor x86_gdt[1024] = {
31         {}, // The first entry is reserved for the NULL selector.
32         {   // 0x08: data
33                 limit_low: 0xffff,
34                 base_low: 0,
35                 base_mid: 0,
36                 type: 2, // data segment, writable
37                 user: 1,
38                 dpl: 0,
39                 present: 1,
40                 limit_high: 0xff,
41                 sw: 0,
42                 reserved: 0,
43                 opsize: 1,
44                 gran: 1,
45                 base_high: 0
46         },
47         {   // 0x10: code
48                 limit_low: 0xffff,
49                 base_low: 0,
50                 base_mid: 0,
51                 type: 10, // code segment, readable
52                 user: 1,
53                 dpl: 0,
54                 present: 1,
55                 limit_high: 0xff,
56                 sw: 0,
57                 reserved: 0,
58                 opsize: 1,
59                 gran: 1,
60                 base_high: 0
61         },
62         {   // 0x18: TSS
63                 limit_low: sizeof(tss),
64                 base_low: 0,
65                 base_mid: 0,
66                 type: 9,
67                 user: 0,
68                 dpl: 0,
69                 present: 1,
70                 limit_high: 0,
71                 sw: 0,
72                 reserved: 0,
73                 opsize: 0,
74                 gran: 0,
75                 base_high: 0
76         }
77 };
78
79 struct X86DescriptorTablePointer {
80         u8 pad[6];
81         u16 limit;
82         u32 address;
83 };
84
85 X86DescriptorTablePointer x86_gdtr = {
86         // G++ still won't handle complex labelled initializers, so
87         // we have to explicitly initialize pad.
88         
89         pad: { 0, 0, 0, 0, 0, 0 }, 
90         limit: sizeof(x86_gdt),
91         address: reinterpret_cast<u32>(&x86_gdt)
92 };
93
94 X86DescriptorTablePointer x86_gdtr_phys = {
95         pad: { 0, 0, 0, 0, 0, 0 }, 
96         limit: sizeof(x86_gdt),
97         address: reinterpret_cast<u32>(&x86_gdt) - KERNEL_START
98 };
99
100 struct X86InterruptDescriptor {
101         u16 offset_low;
102         u16 selector;
103         u8 stack_index:3;
104         u8 reserved:5;
105         u8 type:4;
106         u8 user:1;
107         u8 dpl:2;
108         u8 present:1;
109         u16 offset_high;
110 };
111
112 static X86InterruptDescriptor idt[256];
113
114 static X86DescriptorTablePointer idtr = {
115         pad: { 0, 0, 0, 0, 0, 0 }, 
116         limit: sizeof(idt),
117         address: reinterpret_cast<u32>(&idt)
118 };
119
120 // Set a gate for INT num to start executing at addr.  
121 //
122 // If ints_off is set, then interrupts will remain disabled until
123 // software enables them; otherwise, the interrupt flag will have the
124 // same state as in the code that was interrupted.
125 //
126 // If user is true, then this gate can be called directly from
127 // userspace with the INT instruction.  Otherwise, usermode
128 // INT to this gate will cause a GPF, but it may still be reached
129 // from user code via hardware interrupt or exception.
130 // 
131 // If stack_index is non-zero, use the specified alternate stack even if
132 // interrupting kernel code.
133
134 static void set_int_gate(int num, void *addrptr, bool ints_off = false,
135                          bool user = false, int stack_index = 0)
136 {
137         u32 addr = (u32)addrptr;
138
139         X86InterruptDescriptor desc = {
140                 offset_low: addr & 0xffff,
141                 selector: 0x10,
142                 stack_index: stack_index,
143                 reserved: 0,
144                 type: ints_off ? 14 : 15,
145                 user: 0,
146                 dpl: user ? 3 : 0,
147                 present: 1,
148                 offset_high: (addr >> 16) & 0xffff,
149         };
150         
151         idt[num] = desc;
152 }
153
154 extern int x86_diverr, x86_debug, x86_breakpoint;
155 extern int x86_gpf, x86_page_fault, x86_invalid_insn;
156 extern int x86_int98_entry, x86_int99_entry;
157 extern void *x86_irqs[256];
158
159 namespace Arch {
160 namespace Priv {
161         void set_idt()
162         {
163                 // GCC 4.0 pukes on "m" (&idtr.limit), saying it's not
164                 // directly addressable.
165                 
166                 asm volatile("lidtl 6(%0)" : : "r" (&idtr) : "memory");
167                 
168                 set_int_gate(0, &x86_diverr);
169                 set_int_gate(1, &x86_debug);
170                 set_int_gate(3, &x86_breakpoint);
171                 set_int_gate(6, &x86_invalid_insn);
172                 set_int_gate(13, &x86_gpf);
173                 set_int_gate(14, &x86_page_fault, true);
174                 set_int_gate(0x98, &x86_int98_entry, false, true);
175                 set_int_gate(0x99, &x86_int99_entry, false, true);
176                 
177                 for (int i = 0x20; i < 0x30; i++)
178                         set_int_gate(i, x86_irqs[i], true);
179         }
180 }
181 }