]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x86/descriptors.cc
minor doc updates
[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: kernel 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: 0xf,
41                 sw: 0,
42                 reserved: 0,
43                 opsize: 1,
44                 gran: 1,
45                 base_high: 0
46         },
47         {   // 0x10: kernel 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: 0xf,
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         {   // 0x23: user data
78                 limit_low: 0xffff,
79                 base_low: 0,
80                 base_mid: 0,
81                 type: 2, // data segment, writable
82                 user: 1,
83                 dpl: 3,
84                 present: 1,
85                 limit_high: 0x7,
86                 sw: 0,
87                 reserved: 0,
88                 opsize: 1,
89                 gran: 1,
90                 base_high: 0
91         },
92         {   // 0x2b: code
93                 limit_low: 0xffff,
94                 base_low: 0,
95                 base_mid: 0,
96                 type: 10, // code segment, readable
97                 user: 1,
98                 dpl: 3,
99                 present: 1,
100                 limit_high: 0x7,
101                 sw: 0,
102                 reserved: 0,
103                 opsize: 1,
104                 gran: 1,
105                 base_high: 0
106         },
107 };
108
109 struct X86DescriptorTablePointer {
110         u8 pad[6];
111         u16 limit;
112         u32 address;
113 };
114
115 X86DescriptorTablePointer x86_gdtr = {
116         // G++ still won't handle complex labelled initializers, so
117         // we have to explicitly initialize pad.
118         
119         pad: { 0, 0, 0, 0, 0, 0 }, 
120         limit: sizeof(x86_gdt),
121         address: reinterpret_cast<u32>(&x86_gdt)
122 };
123
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
128 };
129
130 struct X86InterruptDescriptor {
131         u16 offset_low;
132         u16 selector;
133         u8 stack_index:3;
134         u8 reserved:5;
135         u8 type:4;
136         u8 user:1;
137         u8 dpl:2;
138         u8 present:1;
139         u16 offset_high;
140 };
141
142 static X86InterruptDescriptor idt[256];
143
144 static X86DescriptorTablePointer idtr = {
145         pad: { 0, 0, 0, 0, 0, 0 }, 
146         limit: sizeof(idt),
147         address: reinterpret_cast<u32>(&idt)
148 };
149
150 // Set a gate for INT num to start executing at addr.  
151 //
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.
155 //
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.
160 // 
161 // If stack_index is non-zero, use the specified alternate stack even if
162 // interrupting kernel code.
163
164 static void set_int_gate(int num, void *addrptr, bool ints_off = false,
165                          bool user = false, int stack_index = 0)
166 {
167         u32 addr = (u32)addrptr;
168
169         X86InterruptDescriptor desc = {
170                 offset_low: addr & 0xffff,
171                 selector: 0x10,
172                 stack_index: stack_index,
173                 reserved: 0,
174                 type: ints_off ? 14 : 15,
175                 user: 0,
176                 dpl: user ? 3 : 0,
177                 present: 1,
178                 offset_high: (addr >> 16) & 0xffff,
179         };
180         
181         idt[num] = desc;
182 }
183
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];
188
189 namespace Arch {
190 namespace Priv {
191         void set_idt()
192         {
193                 // GCC 4.0 pukes on "m" (&idtr.limit), saying it's not
194                 // directly addressable.
195                 
196                 asm volatile("lidtl 6(%0)" : : "r" (&idtr) : "memory");
197                 
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);
208                 
209                 for (int i = 0x20; i < 0x30; i++)
210                         set_int_gate(i, x86_irqs[i], true);
211         }
212 }
213 }