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);
96 Pseudo_descriptor desc(_idt, _idt_max*sizeof(Idt_entry)-1);
101 * IDT patching function.
102 * Allows to change interrupt gate vectors at runtime.
103 * It makes the IDT writable for the duration of this operation.
104 * @param vector interrupt vector to be modified
105 * @param func new handler function for this interrupt vector
106 * @param user true if user mode can use this vector, false otherwise
110 Idt::set_entry(unsigned vector, Address entry, bool user)
112 assert (vector < _idt_max);
116 Idt_entry *entries = (Idt_entry*)_idt;
118 entries[vector] = Idt_entry(entry, Gdt::gdt_code_kernel,
119 Idt_entry::Access_intr_gate |
120 (user ? Idt_entry::Access_user
121 : Idt_entry::Access_kernel));
123 entries[vector].clear();
130 Idt::get_entry(unsigned vector)
132 assert (vector < _idt_max);
133 Idt_entry *entries = (Idt_entry*)_idt;
134 return entries[vector].offset();
145 //---------------------------------------------------------------------------
146 IMPLEMENTATION[ia32 | amd64]:
152 * IDT loading function.
153 * Loads IDT base and limit into the CPU.
154 * @param desc IDT descriptor (base address, limit)
158 Idt::set(Pseudo_descriptor *desc)
160 asm volatile ("lidt %0" : : "m" (*desc));
165 Idt::get(Pseudo_descriptor *desc)
167 asm volatile ("sidt %0" : "=m" (*desc) : : "memory");
170 extern "C" void entry_int_timer();
171 extern "C" void entry_int_timer_slow();
172 extern "C" void entry_int_timer_stop();
173 extern "C" void entry_int7();
174 extern "C" void entry_intf();
175 extern "C" void entry_int_pic_ignore();
178 * Set IDT vector to the normal timer interrupt handler.
182 Idt::set_vectors_run()
184 Address func = (Config::esc_hack || Config::watchdog ||
185 Config::serial_esc==Config::SERIAL_ESC_NOIRQ)
186 ? (Address)entry_int_timer_slow // slower for debugging
187 : (Address)entry_int_timer; // non-debugging
189 set_entry(Config::scheduler_irq_vector, func, false);
190 if (!Irq_chip::hw_chip->is_free(0x7))
191 Irq_chip::hw_chip->reset(0x07);
193 if (!Irq_chip::hw_chip->is_free(0xf))
194 Irq_chip::hw_chip->reset(0x0f);
198 * Set IDT vector to a dummy vector if Config::getchar_does_hlt is true.
202 Idt::set_vectors_stop()
204 // acknowledge timer interrupt once to keep timer interrupt alive because
205 // we could be called from thread_timer_interrupt_slow() before ack
206 Timer::acknowledge();
208 // set timer interrupt to dummy doing nothing
209 set_entry(Config::scheduler_irq_vector, (Address)entry_int_timer_stop, false);
211 // From ``8259A PROGRAMMABLE INTERRUPT CONTROLLER (8259A 8259A-2)'': If no
212 // interrupt request is present at step 4 of either sequence (i. e. the
213 // request was too short in duration) the 8259A will issue an interrupt
214 // level 7. Both the vectoring bytes and the CAS lines will look like an
215 // interrupt level 7 was requested.
216 set_entry(0x27, (Address)entry_int_pic_ignore, false);
217 set_entry(0x2f, (Address)entry_int_pic_ignore, false);
221 //---------------------------------------------------------------------------
224 #include "emulation.h"
228 Idt::set(Pseudo_descriptor *desc)
230 Emulation::lidt(desc);
235 Idt::get(Pseudo_descriptor *desc)
237 Emulation::sidt(desc);
242 Idt::set_vectors_run()
244 extern char entry_int_timer[];
245 set_entry(Config::scheduler_irq_vector, (Address)entry_int_timer, false);