2 * Fiasco Interrupt Descriptor Table (IDT) Code
9 #include "mem_layout.h"
17 friend class Jdb_kern_info_bench;
19 // idt entries for 0x20 CPU exceptions, 0x10 IRQs, 7 syscalls,
20 // 0x3e/0x3f for APIC exceptions
21 static const unsigned _idt_max = 0xa0;
23 static const Address _idt = Mem_layout::Idt;
35 #include "vmem_alloc.h"
38 * IDT write-protect/write-unprotect function.
39 * @param writable true if IDT should be made writable, false otherwise
43 Idt::set_writable (bool writable)
45 Pdir::Iter e = Kmem::dir()->walk(Virt_addr(_idt));
47 // Make sure page directory entry is valid and not a 4MB page
48 assert (e.e->valid() && e.shift() < Config::SUPERPAGE_SHIFT);
51 e.e->add_attr(Pt_entry::Writable); // Make read-write
53 e.e->del_attr(Pt_entry::Writable); // Make read-only
55 Mem_unit::tlb_flush (_idt);
58 PUBLIC static FIASCO_INIT
60 Idt::init_table(Idt_init_entry *src)
62 Idt_entry *entries = (Idt_entry*)_idt;
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);
75 * IDT initialization function. Sets up initial interrupt vectors.
76 * It also write-protects the IDT because of the infamous Pentium F00F bug.
78 PUBLIC static FIASCO_INIT
82 if (!Vmem_alloc::page_alloc ((void *) _idt, Vmem_alloc::ZERO_FILL))
83 panic ("IDT allocation failure");
85 init_table((Idt_init_entry*)&idt_init_table);
97 Pseudo_descriptor desc(_idt, _idt_max*sizeof(Idt_entry)-1);
102 * IDT patching function.
103 * Allows to change interrupt gate vectors at runtime.
104 * It makes the IDT writable for the duration of this operation.
105 * @param vector interrupt vector to be modified
106 * @param func new handler function for this interrupt vector
107 * @param user true if user mode can use this vector, false otherwise
111 Idt::set_entry(unsigned vector, Address entry, bool user)
113 assert (vector < _idt_max);
117 Idt_entry *entries = (Idt_entry*)_idt;
119 entries[vector] = Idt_entry(entry, Gdt::gdt_code_kernel,
120 Idt_entry::Access_intr_gate |
121 (user ? Idt_entry::Access_user
122 : Idt_entry::Access_kernel));
124 entries[vector].clear();
126 set_writable (false);
131 Idt::get_entry(unsigned vector)
133 assert (vector < _idt_max);
134 Idt_entry *entries = (Idt_entry*)_idt;
135 return entries[vector].offset();
146 //---------------------------------------------------------------------------
147 IMPLEMENTATION[ia32 | amd64]:
153 * IDT loading function.
154 * Loads IDT base and limit into the CPU.
155 * @param desc IDT descriptor (base address, limit)
159 Idt::set (Pseudo_descriptor *desc)
161 asm volatile ("lidt %0" : : "m" (*desc));
166 Idt::get (Pseudo_descriptor *desc)
168 asm volatile ("sidt %0" : "=m" (*desc) : : "memory");
171 extern "C" void entry_int_timer();
172 extern "C" void entry_int_timer_slow();
173 extern "C" void entry_int_timer_stop();
174 extern "C" void entry_int7();
175 extern "C" void entry_intf();
176 extern "C" void entry_int_pic_ignore();
179 * Set IDT vector to the normal timer interrupt handler.
183 Idt::set_vectors_run()
185 Address func = (Config::esc_hack || Config::watchdog ||
186 Config::serial_esc==Config::SERIAL_ESC_NOIRQ)
187 ? (Address)entry_int_timer_slow // slower for debugging
188 : (Address)entry_int_timer; // non-debugging
190 set_entry (Config::scheduler_irq_vector, func, false);
191 if (!Irq_chip::hw_chip->is_free(0x7))
192 Irq_chip::hw_chip->reset(0x07);
194 if (!Irq_chip::hw_chip->is_free(0xf))
195 Irq_chip::hw_chip->reset(0x0f);
199 * Set IDT vector to a dummy vector if Config::getchar_does_hlt is true.
203 Idt::set_vectors_stop()
205 // acknowledge timer interrupt once to keep timer interrupt alive because
206 // we could be called from thread_timer_interrupt_slow() before ack
207 Timer::acknowledge();
209 // set timer interrupt to dummy doing nothing
210 set_entry(Config::scheduler_irq_vector,
211 (Address) entry_int_timer_stop, false);
213 // From ``8259A PROGRAMMABLE INTERRUPT CONTROLLER (8259A 8259A-2)'': If no
214 // interrupt request is present at step 4 of either sequence (i. e. the
215 // request was too short in duration) the 8259A will issue an interrupt
216 // level 7. Both the vectoring bytes and the CAS lines will look like an
217 // interrupt level 7 was requested.
218 set_entry(0x27, (Address) entry_int_pic_ignore, false);
219 set_entry(0x2f, (Address) entry_int_pic_ignore, false);
223 //---------------------------------------------------------------------------
226 #include "emulation.h"
230 Idt::set (Pseudo_descriptor *desc)
232 Emulation::lidt (desc);
237 Idt::get (Pseudo_descriptor *desc)
239 Emulation::sidt (desc);
244 Idt::set_vectors_run()
246 extern char entry_int_timer[];
247 set_entry (Config::scheduler_irq_vector, (Address)entry_int_timer, false);