]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/idt.cpp
be65a8acabb7665e35c959d37c252c406a901a82
[l4.git] / kernel / fiasco / src / kern / ia32 / idt.cpp
1 /*
2  * Fiasco Interrupt Descriptor Table (IDT) Code
3  */
4
5 INTERFACE:
6
7 #include "initcalls.h"
8 #include "kmem.h"
9 #include "mem_layout.h"
10 #include "types.h"
11 #include "x86desc.h"
12
13 class Idt_init_entry;
14
15 class Idt
16 {
17   friend class Jdb_kern_info_bench;
18 public:
19   // idt entries for 0x20 CPU exceptions, 0x10 IRQs, 7 syscalls,
20   // 0x3e/0x3f for APIC exceptions
21   static const unsigned _idt_max = 0xa0;
22 private:
23   static const Address  _idt = Mem_layout::Idt;
24 };
25
26 IMPLEMENTATION:
27
28 #include <cassert>
29 #include "gdt.h"
30 #include "idt_init.h"
31 #include "irq_chip.h"
32 #include "mem_unit.h"
33 #include "paging.h"
34 #include "panic.h"
35 #include "vmem_alloc.h"
36
37 /**
38  * IDT write-protect/write-unprotect function.
39  * @param writable true if IDT should be made writable, false otherwise
40  */
41 PRIVATE static
42 void
43 Idt::set_writable(bool writable)
44 {
45   Pdir::Iter e = Kmem::dir()->walk(Virt_addr(_idt));
46
47   // Make sure page directory entry is valid and not a 4MB page
48   assert (e.e->valid() && e.shift() < Config::SUPERPAGE_SHIFT);
49
50   if (writable)
51     e.e->add_attr(Pt_entry::Writable); // Make read-write
52   else
53     e.e->del_attr(Pt_entry::Writable); // Make read-only
54
55   Mem_unit::tlb_flush (_idt);
56 }
57
58 PUBLIC static FIASCO_INIT
59 void
60 Idt::init_table(Idt_init_entry *src)
61 {
62   Idt_entry *entries = (Idt_entry*)_idt;
63
64   while (src->entry)
65     {
66       entries[src->vector] = 
67         ((src->type & 0x1f) == 0x05) // task gate?
68           ? Idt_entry(src->entry, src->type)
69           : Idt_entry(src->entry, Gdt::gdt_code_kernel, src->type);
70       src++;
71     }
72 }
73
74 /**
75  * IDT initialization function. Sets up initial interrupt vectors.
76  * It also write-protects the IDT because of the infamous Pentium F00F bug.
77  */
78 PUBLIC static FIASCO_INIT
79 void
80 Idt::init()
81 {
82   if (!Vmem_alloc::page_alloc((void *) _idt, Vmem_alloc::ZERO_FILL))
83     panic("IDT allocation failure");
84
85   init_table((Idt_init_entry*)&idt_init_table);
86   load();
87
88   set_writable(false);
89 }
90
91
92 PUBLIC static
93 void
94 Idt::load()
95 {
96   Pseudo_descriptor desc(_idt, _idt_max*sizeof(Idt_entry)-1);
97   set(&desc);
98 }
99
100 PUBLIC static
101 void
102 Idt::set_entry(unsigned vector, Idt_entry entry)
103 {
104   assert (vector < _idt_max);
105
106   set_writable(true);
107
108   Idt_entry *entries = (Idt_entry*)_idt;
109   entries[vector] = entry;
110   set_writable(false);
111 }
112
113 PUBLIC static
114 Idt_entry const &
115 Idt::get(unsigned vector)
116 {
117   assert (vector < _idt_max);
118
119   return ((Idt_entry*)_idt)[vector];
120 }
121
122 /**
123  * IDT patching function.
124  * Allows to change interrupt gate vectors at runtime.
125  * It makes the IDT writable for the duration of this operation.
126  * @param vector interrupt vector to be modified
127  * @param func new handler function for this interrupt vector
128  * @param user true if user mode can use this vector, false otherwise
129  */
130 PUBLIC static
131 void
132 Idt::set_entry(unsigned vector, Address entry, bool user)
133 {
134   assert (vector < _idt_max);
135
136   set_writable(true);
137
138   Idt_entry *entries = (Idt_entry*)_idt;
139   if (entry)
140     entries[vector] = Idt_entry(entry, Gdt::gdt_code_kernel,
141                                 Idt_entry::Access_intr_gate |
142                                 (user ? Idt_entry::Access_user 
143                                       : Idt_entry::Access_kernel));
144   else
145     entries[vector].clear();
146
147   set_writable(false);
148 }
149
150 PUBLIC static
151 Address
152 Idt::get_entry(unsigned vector)
153 {
154   assert (vector < _idt_max);
155   Idt_entry *entries = (Idt_entry*)_idt;
156   return entries[vector].offset();
157 }
158
159 PUBLIC static inline
160 Address
161 Idt::idt()
162 {
163   return _idt;
164 }
165
166
167 //---------------------------------------------------------------------------
168 IMPLEMENTATION[ia32 | amd64]:
169
170 #include "config.h"
171
172 /**
173  * IDT loading function.
174  * Loads IDT base and limit into the CPU.
175   * @param desc IDT descriptor (base address, limit)
176   */  
177 PUBLIC static inline
178 void
179 Idt::set(Pseudo_descriptor *desc)
180 {
181   asm volatile ("lidt %0" : : "m" (*desc));
182 }
183
184 PUBLIC static inline
185 void
186 Idt::get(Pseudo_descriptor *desc)
187 {
188   asm volatile ("sidt %0" : "=m" (*desc) : : "memory");
189 }
190
191 extern "C" void entry_int_timer();
192 extern "C" void entry_int_timer_slow();
193 extern "C" void entry_int7();
194 extern "C" void entry_intf();
195 extern "C" void entry_int_pic_ignore();
196
197 /**
198  * Set IDT vector to the normal timer interrupt handler.
199  */
200 PUBLIC static
201 void
202 Idt::set_vectors_run()
203 {
204   Address func = (Config::esc_hack || Config::watchdog ||
205                   Config::serial_esc==Config::SERIAL_ESC_NOIRQ)
206                     ? (Address)entry_int_timer_slow // slower for debugging
207                     : (Address)entry_int_timer;     // non-debugging
208
209   set_entry(Config::scheduler_irq_vector, func, false);
210 #if 0
211   if (!Irq_chip::hw_chip->is_free(0x7))
212     Irq_chip::hw_chip->reset(0x07);
213
214   if (!Irq_chip::hw_chip->is_free(0xf))
215     Irq_chip::hw_chip->reset(0x0f);
216 #endif
217 }
218
219
220 //---------------------------------------------------------------------------
221 IMPLEMENTATION[ux]:
222
223 #include "emulation.h"
224
225 PUBLIC static
226 void
227 Idt::set(Pseudo_descriptor *desc)
228 {
229   Emulation::lidt(desc);
230 }
231
232 PUBLIC static
233 void
234 Idt::get(Pseudo_descriptor *desc)
235 {
236   Emulation::sidt(desc);
237 }