6 #include "irq_chip_ia32.h"
7 #include <cxx/bitfield>
20 enum Delivery { Fixed, Lowest_prio, SMI, NMI = 4, INIT, ExtINT = 7 };
21 enum Dest_mode { Physical, Logical };
22 enum Polarity { High_active, Low_active };
23 enum Trigger { Edge, Level };
26 Io_apic_entry(Unsigned8 vector, Delivery d, Dest_mode dm, Polarity p,
27 Trigger t, Unsigned32 dest)
28 : _e( vector_bfm_t::val(vector) | delivery_bfm_t::val(d) | mask_bfm_t::val(1)
29 | dest_mode_bfm_t::val(dm) | polarity_bfm_t::val(p)
30 | trigger_bfm_t::val(t) | dest_bfm_t::val(dest >> 24))
33 CXX_BITFIELD_MEMBER( 0, 7, vector, _e);
34 CXX_BITFIELD_MEMBER( 8, 10, delivery, _e);
35 CXX_BITFIELD_MEMBER(11, 11, dest_mode, _e);
36 CXX_BITFIELD_MEMBER(13, 13, polarity, _e);
37 CXX_BITFIELD_MEMBER(15, 15, trigger, _e);
38 CXX_BITFIELD_MEMBER(16, 16, mask, _e);
39 // support for IRQ remapping
40 CXX_BITFIELD_MEMBER(48, 48, format, _e);
41 // support for IRQ remapping
42 CXX_BITFIELD_MEMBER(49, 63, irt_index, _e);
43 CXX_BITFIELD_MEMBER(56, 63, dest, _e);
47 class Io_apic : public Irq_chip_icu, protected Irq_chip_ia32
49 friend class Jdb_io_apic_module;
50 friend class Irq_chip_ia32;
52 unsigned nr_irqs() const override { return Irq_chip_ia32::nr_irqs(); }
53 bool reserve(Mword pin) override { return Irq_chip_ia32::reserve(pin); }
54 Irq_base *irq(Mword pin) const override { return Irq_chip_ia32::irq(pin); }
59 Unsigned32 volatile adr;
61 Unsigned32 volatile data;
63 unsigned num_entries();
65 void modify(int reg, Mword set_bits, Mword del_bits);
66 void write(int reg, Mword value);
67 } __attribute__((packed));
70 mutable Spin_lock<> _l;
74 static unsigned _nr_irqs;
75 static Io_apic *_first;
76 static Acpi_madt const *_madt;
77 static Io_apic_entry *_state_save_area;
80 class Io_apic_mgr : public Irq_mgr, public Pm_object
83 Io_apic_mgr() { register_pm(Cpu_number::boot_cpu()); }
94 #include "lock_guard.h"
95 #include "boot_alloc.h"
98 enum { Print_info = 0 };
100 Acpi_madt const *Io_apic::_madt;
101 unsigned Io_apic::_nr_irqs;
102 Io_apic *Io_apic::_first;
103 Io_apic_entry *Io_apic::_state_save_area;
107 Io_apic_mgr::chip(Mword irq) const
109 Io_apic *a = Io_apic::find_apic(irq);
111 return Irq(a, irq - a->gsi_offset());
118 Io_apic_mgr::nr_irqs() const
120 return Io_apic::total_irqs();
125 Io_apic_mgr::nr_msis() const
129 Io_apic_mgr::legacy_override(Mword i)
130 { return Io_apic::legacy_override(i); }
133 Io_apic_mgr::pm_on_suspend(Cpu_number cpu)
136 assert (cpu == Cpu_number::boot_cpu());
137 Io_apic::save_state();
141 Io_apic_mgr::pm_on_resume(Cpu_number cpu)
144 assert (cpu == Cpu_number::boot_cpu());
145 Pic::disable_all_save();
146 Io_apic::restore_state(true);
152 Io_apic::Apic::read(int reg)
155 asm volatile ("": : :"memory");
161 Io_apic::Apic::modify(int reg, Mword set_bits, Mword del_bits)
165 asm volatile ("": : :"memory");
174 Io_apic::Apic::write(int reg, Mword value)
177 asm volatile ("": : :"memory");
183 Io_apic::Apic::num_entries()
185 return (read(1) >> 16) & 0xff;
189 Io_apic::Io_apic(Unsigned64 phys, unsigned gsi_base)
190 : Irq_chip_ia32(0), _l(Spin_lock<>::Unlocked),
191 _offset(gsi_base), _next(0)
194 printf("IO-APIC: addr=%lx\n", (Mword)phys);
197 Address va = Mem_layout::alloc_io_vmem(Config::PAGE_SIZE);
200 Kmem::map_phys_page(phys, va, false, true, &offs);
202 Kip::k()->add_mem_region(Mem_desc(phys, phys + Config::PAGE_SIZE -1, Mem_desc::Reserved));
204 Io_apic::Apic *a = (Io_apic::Apic*)(va + offs);
208 _irqs = a->num_entries() + 1;
209 _entry = new Irq_entry_code[_irqs];
211 if ((_offset + nr_irqs()) > _nr_irqs)
212 _nr_irqs = _offset + nr_irqs();
214 Io_apic **c = &_first;
215 while (*c && (*c)->_offset < _offset)
221 Mword cpu_phys = ::Apic::apic.cpu(Cpu_number::boot_cpu())->apic_id();
223 for (unsigned i = 0; i < _irqs; ++i)
226 Io_apic_entry e(v, Io_apic_entry::Fixed, Io_apic_entry::Physical,
227 Io_apic_entry::High_active, Io_apic_entry::Edge,
234 PUBLIC inline NEEDS["assert.h", "lock_guard.h"]
236 Io_apic::read_entry(unsigned i) const
238 auto g = lock_guard(_l);
240 //assert(i <= num_entries());
241 e._e = (Unsigned64)_apic->read(0x10+2*i) | (((Unsigned64)_apic->read(0x11+2*i)) << 32);
246 PUBLIC inline NEEDS["assert.h", "lock_guard.h"]
248 Io_apic::write_entry(unsigned i, Io_apic_entry const &e)
250 auto g = lock_guard(_l);
251 //assert(i <= num_entries());
252 _apic->write(0x10+2*i, e._e);
253 _apic->write(0x11+2*i, e._e >> 32);
256 PROTECTED static FIASCO_INIT
258 Io_apic::read_overrides()
260 for (unsigned tmp = 0;; ++tmp)
262 auto irq = _madt->find<Acpi_madt::Irq_source>(tmp);
268 printf("IO-APIC: ovr[%2u] %02x -> %x %x\n",
269 tmp, (unsigned)irq->src, irq->irq, (unsigned)irq->flags);
271 if (irq->irq >= _nr_irqs)
273 WARN("IO-APIC: warning override %02x -> %x (flags=%x) points to invalid GSI\n",
274 (unsigned)irq->src, irq->irq, (unsigned)irq->flags);
278 Io_apic *ioapic = find_apic(irq->irq);
280 unsigned pin = irq->irq - ioapic->gsi_offset();
281 Irq_chip::Mode mode = ioapic->get_mode(pin);
283 unsigned pol = irq->flags & 0x3;
284 unsigned trg = (irq->flags >> 2) & 0x3;
289 case 1: mode.polarity() = Mode::Polarity_high; break;
291 case 3: mode.polarity() = Mode::Polarity_low; break;
298 case 1: mode.level_triggered() = Mode::Trigger_edge; break;
300 case 3: mode.level_triggered() = Mode::Trigger_level; break;
303 ioapic->set_mode(pin, mode);
308 PUBLIC static FIASCO_INIT
310 Io_apic::lookup_madt()
315 _madt = Acpi::find<Acpi_madt const *>("APIC");
320 Acpi_madt const *Io_apic::madt() { return _madt; }
322 PUBLIC static FIASCO_INIT
324 Io_apic::init_scan_apics()
326 auto madt = lookup_madt();
330 WARN("Could not find APIC in RSDT nor XSDT, skipping init\n");
336 auto ioapic = madt->find<Acpi_madt::Io_apic>(n_apics);
339 Io_apic *apic = new Boot_object<Io_apic>(ioapic->adr, ioapic->irq_base);
343 printf("IO-APIC[%2d]: pins %u\n", n_apics, apic->nr_irqs());
350 WARN("IO-APIC: Could not find IO-APIC in MADT, skip init\n");
355 printf("IO-APIC: dual 8259: %s\n", madt->apic_flags & 1 ? "yes" : "no");
361 PUBLIC static FIASCO_INIT
363 Io_apic::init(Cpu_number)
366 Irq_mgr::mgr = new Boot_object<Io_apic_mgr>();
368 _state_save_area = new Boot_object<Io_apic_entry>[_nr_irqs];
371 // in the case we use the IO-APIC not the PIC we can dynamically use
372 // INT vectors from 0x20 to 0x2f too
373 _vectors.add_free(0x20, 0x30);
378 Io_apic::save_state()
380 for (Io_apic *a = _first; a; a = a->_next)
381 for (unsigned i = 0; i < a->_irqs; ++i)
382 _state_save_area[a->_offset + i] = a->read_entry(i);
387 Io_apic::restore_state(bool set_boot_cpu = false)
391 cpu_phys = ::Apic::apic.cpu(Cpu_number::boot_cpu())->apic_id();
393 for (Io_apic *a = _first; a; a = a->_next)
394 for (unsigned i = 0; i < a->_irqs; ++i)
396 Io_apic_entry e = _state_save_area[a->_offset + i];
397 if (set_boot_cpu && e.format() == 0)
399 a->write_entry(i, e);
405 Io_apic::total_irqs()
410 Io_apic::legacy_override(unsigned i)
418 Acpi_madt::Irq_source const *irq
419 = static_cast<Acpi_madt::Irq_source const *>(_madt->find(Acpi_madt::Irq_src_ovr, tmp));
434 for (unsigned i = 0; i < _irqs; ++i)
436 Io_apic_entry e = read_entry(i);
437 printf(" PIN[%2u%c]: vector=%2x, del=%u, dm=%s, dest=%u (%s, %s)\n",
438 i, e.mask() ? 'm' : '.',
439 (unsigned)e.vector(), (unsigned)e.delivery(), e.dest_mode() ? "logical" : "physical",
441 e.polarity() ? "low" : "high",
442 e.trigger() ? "level" : "edge");
449 Io_apic::valid() const { return _apic; }
451 PRIVATE inline NEEDS["assert.h", "lock_guard.h"]
453 Io_apic::_mask(unsigned irq)
455 auto g = lock_guard(_l);
456 //assert(irq <= _apic->num_entries());
457 _apic->modify(0x10 + irq * 2, 1UL << 16, 0);
460 PRIVATE inline NEEDS["assert.h", "lock_guard.h"]
462 Io_apic::_unmask(unsigned irq)
464 auto g = lock_guard(_l);
465 //assert(irq <= _apic->num_entries());
466 _apic->modify(0x10 + irq * 2, 0, 1UL << 16);
469 PUBLIC inline NEEDS["assert.h", "lock_guard.h"]
471 Io_apic::masked(unsigned irq)
473 auto g = lock_guard(_l);
474 //assert(irq <= _apic->num_entries());
475 return _apic->read(0x10 + irq * 2) & (1UL << 16);
485 PUBLIC inline NEEDS["assert.h", "lock_guard.h"]
487 Io_apic::set_dest(unsigned irq, Mword dst)
489 auto g = lock_guard(_l);
490 //assert(irq <= _apic->num_entries());
491 _apic->modify(0x11 + irq * 2, dst & (~0UL << 24), ~0UL << 24);
496 Io_apic::gsi_offset() const { return _offset; }
500 Io_apic::find_apic(unsigned irqnum)
502 for (Io_apic *a = _first; a; a = a->_next)
504 if (a->_offset <= irqnum && a->_offset + a->_irqs > irqnum)
511 Io_apic::mask(Mword irq) override
518 Io_apic::ack(Mword) override
524 Io_apic::mask_and_ack(Mword irq) override
532 Io_apic::unmask(Mword irq) override
538 Io_apic::set_cpu(Mword irq, Cpu_number cpu) override
540 set_dest(irq, ::Apic::apic.cpu(cpu)->apic_id());
543 PROTECTED static inline
545 Io_apic::to_io_apic_trigger(Irq_chip::Mode mode)
547 return mode.level_triggered()
548 ? Io_apic_entry::Level
549 : Io_apic_entry::Edge;
552 PROTECTED static inline
554 Io_apic::to_io_apic_polarity(Irq_chip::Mode mode)
556 return mode.polarity() == Irq_chip::Mode::Polarity_high
557 ? Io_apic_entry::High_active
558 : Io_apic_entry::Low_active;
562 Io_apic::set_mode(Mword pin, Mode mode) override
564 if (!mode.set_mode())
567 Io_apic_entry e = read_entry(pin);
568 e.polarity() = to_io_apic_polarity(mode);
569 e.trigger() = to_io_apic_trigger(mode);
576 Io_apic::get_mode(Mword pin)
578 Io_apic_entry e = read_entry(pin);
579 Mode m(Mode::Set_irq_mode);
580 m.polarity() = e.polarity() == Io_apic_entry::High_active
581 ? Mode::Polarity_high
582 : Mode::Polarity_low;
583 m.level_triggered() = e.trigger() == Io_apic_entry::Level
584 ? Mode::Trigger_level
585 : Mode::Trigger_edge;
591 Io_apic::is_edge_triggered(Mword pin) const override
593 Io_apic_entry e = read_entry(pin);
594 return e.trigger() == Io_apic_entry::Edge;
599 Io_apic::alloc(Irq_base *irq, Mword pin) override
601 unsigned v = valloc<Io_apic>(irq, pin, 0);
606 Io_apic_entry e = read_entry(pin);
614 Io_apic::unbind(Irq_base *irq) override
616 extern char entry_int_apic_ignore[];
617 Mword n = irq->pin();
619 vfree(irq, &entry_int_apic_ignore);
620 Irq_chip_icu::unbind(irq);
628 IMPLEMENTATION [debug]:
632 Io_apic::chip_type() const override
633 { return "IO-APIC"; }