]> git.buserror.net Git - polintos/scott/priv.git/blob - kernel/arch/x64/descriptors.cc
minor doc updates
[polintos/scott/priv.git] / kernel / arch / x64 / descriptors.cc
1 // arch/x64/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 x64_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                 code64: 0,
43                 opsize: 1,
44                 gran: 1,
45                 base_high: 0
46         },
47         {   // 0x10: 32-bit 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                 code64: 0,
58                 opsize: 1,
59                 gran: 1,
60                 base_high: 0
61         },
62         {   // 0x18: 64-bit code
63                 limit_low: 0xffff,
64                 base_low: 0,
65                 base_mid: 0,
66                 type: 10, // code segment, readable
67                 user: 1,
68                 dpl: 0,
69                 present: 1,
70                 limit_high: 0xff,
71                 sw: 0,
72                 code64: 1,
73                 opsize: 0,
74                 gran: 1,
75                 base_high: 0
76         },
77         {   // 0x20: TSS
78                 limit_low: sizeof(TSS) - 4,
79                 base_low: 0,
80                 base_mid: 0,
81                 type: 9,
82                 user: 0,
83                 dpl: 0,
84                 present: 1,
85                 limit_high: 0,
86                 sw: 0,
87                 code64: 0,
88                 opsize: 0,
89                 gran: 0,
90                 base_high: 0,
91         },
92         {   // 0x28: TSS high
93         }
94 };
95
96 struct X64DescriptorTablePointer {
97         u8 pad[6];
98         u16 limit;
99         u64 address;
100 };
101
102 X64DescriptorTablePointer x64_gdtr = {
103         // G++ still won't handle complex labelled initializers, so
104         // we have to explicitly initialize pad.
105         
106         pad: { 0, 0, 0, 0, 0, 0 }, 
107         limit: sizeof(x64_gdt),
108         address: reinterpret_cast<u64>(&x64_gdt)
109 };
110
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
115 };
116
117 struct X64InterruptDescriptor {
118         u16 offset_low;
119         u16 selector;
120         u8 stack_index:3;
121         u8 reserved:5;
122         u8 type:4;
123         u8 user:1;
124         u8 dpl:2;
125         u8 present:1;
126         u16 offset_mid;
127         u32 offset_high;
128         u32 reserved2;
129 };
130         
131 static X64InterruptDescriptor idt[256];
132
133 static X64DescriptorTablePointer idtr = {
134         pad: { 0, 0, 0, 0, 0, 0 }, 
135         limit: sizeof(idt),
136         address: reinterpret_cast<u64>(&idt)
137 };
138
139 // Set a gate for INT num to start executing at addr.  
140 //
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.
144 //
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.
149 // 
150 // If stack_index is non-zero, use the specified alternate stack even if
151 // interrupting kernel code.
152
153 static void set_int_gate(int num, void *addrptr, bool ints_off = false,
154                          bool user = false, int stack_index = 0)
155 {
156         u64 addr = (u64)addrptr;
157
158         X64InterruptDescriptor desc = {
159                 offset_low: addr & 0xffff,
160                 selector: 0x18,
161                 stack_index: stack_index,
162                 reserved: 0,
163                 type: ints_off ? 14 : 15,
164                 user: 0,
165                 dpl: user ? 3 : 0,
166                 present: 1,
167                 offset_mid: (addr >> 16) & 0xffff,
168                 offset_high: addr >> 32
169         };
170         
171         idt[num] = desc;
172 }
173
174 extern int x64_diverr, x64_gpf, x64_page_fault, x64_invalid_insn;
175 extern void *x64_irqs[256];
176
177 namespace Arch {
178 namespace Priv {
179         void set_idt()
180         {
181                 // GCC 4.0 pukes on "m" (&idtr.limit), saying it's not
182                 // directly addressable.
183                 
184                 asm volatile("lidtq 6(%0)" : : "r" (&idtr) : "memory");
185                 
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);
190                 
191                 for (int i = 0x20; i < 0x30; i++)
192                         set_int_gate(i, x64_irqs[i]);
193         }
194 }
195 }