6 #include "irq_chip_ia32.h"
18 enum Delivery { Fixed, Lowest_prio, SMI, NMI = 4, INIT, ExtINT = 7 };
19 enum Dest_mode { Physical, Logical };
20 enum Polarity { High_active, Low_active };
21 enum Trigger { Edge, Level };
24 Io_apic_entry(Unsigned8 vector, Delivery d, Dest_mode dm, Polarity p,
25 Trigger t, Unsigned32 dest)
26 : _e( vector_bfm_t::val(vector) | delivery_bfm_t::val(d) | mask_bfm_t::val(1)
27 | dest_mode_bfm_t::val(dm) | polarity_bfm_t::val(p)
28 | trigger_bfm_t::val(t) | dest_bfm_t::val(dest >> 24))
31 CXX_BITFIELD_MEMBER( 0, 7, vector, _e);
32 CXX_BITFIELD_MEMBER( 8, 10, delivery, _e);
33 CXX_BITFIELD_MEMBER(11, 11, dest_mode, _e);
34 CXX_BITFIELD_MEMBER(13, 13, polarity, _e);
35 CXX_BITFIELD_MEMBER(15, 15, trigger, _e);
36 CXX_BITFIELD_MEMBER(16, 16, mask, _e);
37 CXX_BITFIELD_MEMBER(56, 63, dest, _e);
41 class Io_apic : public Irq_chip_ia32
43 friend class Jdb_io_apic_module;
48 Unsigned32 volatile adr;
50 Unsigned32 volatile data;
52 unsigned num_entries();
54 void modify(int reg, Mword set_bits, Mword del_bits);
55 void write(int reg, Mword value);
56 } __attribute__((packed));
63 static unsigned _nr_irqs;
64 static Io_apic *_first;
65 static Acpi_madt const *_madt;
76 #include "lock_guard.h"
77 #include "boot_alloc.h"
79 Acpi_madt const *Io_apic::_madt;
80 unsigned Io_apic::_nr_irqs;
81 Io_apic *Io_apic::_first;
84 class Io_apic_mgr : public Irq_mgr
89 Io_apic_mgr::chip(Mword irq) const
91 Io_apic *a = Io_apic::find_apic(irq);
93 return Irq(a, irq - a->gsi_offset());
100 Io_apic_mgr::nr_irqs() const
102 return Io_apic::total_irqs();
107 Io_apic_mgr::nr_msis() const
111 Io_apic_mgr::legacy_override(Mword i)
112 { return Io_apic::legacy_override(i); }
117 Io_apic::Apic::read(int reg)
120 asm volatile ("": : :"memory");
126 Io_apic::Apic::modify(int reg, Mword set_bits, Mword del_bits)
130 asm volatile ("": : :"memory");
139 Io_apic::Apic::write(int reg, Mword value)
142 asm volatile ("": : :"memory");
148 Io_apic::Apic::num_entries()
150 return (read(1) >> 16) & 0xff;
153 PUBLIC explicit inline
154 Io_apic::Io_apic(Io_apic::Apic *addr, unsigned irqs, unsigned gsi_base)
155 : Irq_chip_ia32(irqs), _apic(addr), _l(Spin_lock<>::Unlocked),
156 _offset(gsi_base), _next(0)
160 PUBLIC inline NEEDS["kdb_ke.h", "lock_guard.h"]
162 Io_apic::read_entry(unsigned i)
164 auto g = lock_guard(_l);
166 //assert_kdb(i <= num_entries());
167 e._e = (Unsigned64)_apic->read(0x10+2*i) | (((Unsigned64)_apic->read(0x11+2*i)) << 32);
172 PUBLIC inline NEEDS["kdb_ke.h", "lock_guard.h"]
174 Io_apic::write_entry(unsigned i, Io_apic_entry const &e)
176 auto g = lock_guard(_l);
177 //assert_kdb(i <= num_entries());
178 _apic->write(0x10+2*i, e._e);
179 _apic->write(0x11+2*i, e._e >> 32);
182 PUBLIC static FIASCO_INIT
184 Io_apic::init(unsigned cpu)
186 _madt = Acpi::find<Acpi_madt const *>("APIC");
190 printf("Could not find APIC in RSDT nor XSDT, skipping init\n");
193 printf("IO-APIC: MADT = %p\n", _madt);
198 Acpi_madt::Io_apic const *ioapic = static_cast<Acpi_madt::Io_apic const *>(_madt->find(Acpi_madt::IOAPIC, n_apics));
201 printf("IO-APIC[%2d]: struct: %p adr=%x\n", n_apics, ioapic, ioapic->adr);
204 Address va = Mem_layout::alloc_io_vmem(Config::PAGE_SIZE);
207 Kmem::map_phys_page(ioapic->adr, va, false, true, &offs);
209 Kip::k()->add_mem_region(Mem_desc(ioapic->adr, ioapic->adr + Config::PAGE_SIZE -1, Mem_desc::Reserved));
211 Io_apic::Apic *a = (Io_apic::Apic*)(va + offs);
214 unsigned const irqs = a->num_entries() + 1;
215 Io_apic *apic = new Boot_object<Io_apic>(a, irqs, ioapic->irq_base);
217 if ((apic->_offset + irqs) > _nr_irqs)
218 _nr_irqs = apic->_offset + irqs;
220 for (unsigned i = 0; i < irqs; ++i)
223 Io_apic_entry e(v, Io_apic_entry::Fixed, Io_apic_entry::Physical,
224 Io_apic_entry::High_active, Io_apic_entry::Edge,
225 ::Apic::apic.cpu(cpu)->apic_id());
226 apic->write_entry(i, e);
229 Io_apic **c = &_first;
230 while (*c && (*c)->_offset < apic->_offset)
236 printf("IO-APIC[%2d]: pins %u\n", n_apics, irqs);
242 printf("IO-APIC: Could not find IO-APIC in MADT, skip init\n");
247 printf("IO-APIC: dual 8259: %s\n", _madt->apic_flags & 1 ? "yes" : "no");
249 for (unsigned tmp = 0;;++tmp)
251 Acpi_madt::Irq_source const *irq
252 = static_cast<Acpi_madt::Irq_source const *>(_madt->find(Acpi_madt::Irq_src_ovr, tmp));
257 printf("IO-APIC: ovr[%2u] %02x -> %x\n", tmp, irq->src, irq->irq);
260 Irq_mgr::mgr = new Boot_object<Io_apic_mgr>();
262 // in the case we use the IO-APIC not the PIC we can dynamically use
263 // INT vectors from 0x20 to 0x2f too
264 _vectors.add_free(0x20, 0x30);
270 Io_apic::total_irqs()
275 Io_apic::legacy_override(unsigned i)
283 Acpi_madt::Irq_source const *irq
284 = static_cast<Acpi_madt::Irq_source const *>(_madt->find(Acpi_madt::Irq_src_ovr, tmp));
299 for (unsigned i = 0; i < _irqs; ++i)
301 Io_apic_entry e = read_entry(i);
302 printf(" PIN[%2u%c]: vector=%2x, del=%u, dm=%s, dest=%u (%s, %s)\n",
303 i, e.mask() ? 'm' : '.',
304 (unsigned)e.vector(), (unsigned)e.delivery(), e.dest_mode() ? "logical" : "physical",
306 e.polarity() ? "low" : "high",
307 e.trigger() ? "level" : "edge");
314 Io_apic::valid() const { return _apic; }
316 PRIVATE inline NEEDS["kdb_ke.h", "lock_guard.h"]
318 Io_apic::_mask(unsigned irq)
320 auto g = lock_guard(_l);
321 //assert_kdb(irq <= _apic->num_entries());
322 _apic->modify(0x10 + irq * 2, 1UL << 16, 0);
325 PRIVATE inline NEEDS["kdb_ke.h", "lock_guard.h"]
327 Io_apic::_unmask(unsigned irq)
329 auto g = lock_guard(_l);
330 //assert_kdb(irq <= _apic->num_entries());
331 _apic->modify(0x10 + irq * 2, 0, 1UL << 16);
334 PUBLIC inline NEEDS["kdb_ke.h", "lock_guard.h"]
336 Io_apic::masked(unsigned irq)
338 auto g = lock_guard(_l);
339 //assert_kdb(irq <= _apic->num_entries());
340 return _apic->read(0x10 + irq * 2) & (1UL << 16);
350 PUBLIC inline NEEDS["kdb_ke.h", "lock_guard.h"]
352 Io_apic::set_dest(unsigned irq, Mword dst)
354 auto g = lock_guard(_l);
355 //assert_kdb(irq <= _apic->num_entries());
356 _apic->modify(0x11 + irq * 2, dst & (~0UL << 24), ~0UL << 24);
361 Io_apic::gsi_offset() const { return _offset; }
365 Io_apic::find_apic(unsigned irqnum)
367 for (Io_apic *a = _first; a; a = a->_next)
369 if (a->_offset <= irqnum && a->_offset + a->_irqs > irqnum)
376 Io_apic::mask(Mword irq)
389 Io_apic::mask_and_ack(Mword irq)
397 Io_apic::unmask(Mword irq)
403 Io_apic::set_cpu(Mword irq, unsigned cpu)
405 set_dest(irq, ::Apic::apic.cpu(cpu)->apic_id());
409 Mword to_io_apic_trigger(unsigned mode)
411 return (mode & Irq_base::Trigger_level)
412 ? Io_apic_entry::Level
413 : Io_apic_entry::Edge;
417 Mword to_io_apic_polarity(unsigned mode)
419 return (mode & Irq_base::Polarity_low)
420 ? Io_apic_entry::Low_active
421 : Io_apic_entry::High_active;
425 Io_apic::set_mode(Mword pin, unsigned mode)
427 if ((mode & Irq_base::Polarity_mask) == Irq_base::Polarity_both)
428 mode = Irq_base::Polarity_low;
430 Io_apic_entry e = read_entry(pin);
431 e.polarity() = to_io_apic_polarity(mode);
432 e.trigger() = to_io_apic_trigger(mode);
439 Io_apic::alloc(Irq_base *irq, Mword pin)
441 unsigned v = valloc(irq, pin, 0);
446 Io_apic_entry e = read_entry(pin);
454 Io_apic::unbind(Irq_base *irq)
456 extern char entry_int_apic_ignore[];
457 Mword n = irq->pin();
459 vfree(irq, &entry_int_apic_ignore);
460 Irq_chip_icu::unbind(irq);
465 Io_apic::chip_type() const
466 { return "IO-APIC"; }