16 enum Delivery { Fixed, Lowest_prio, SMI, NMI = 4, INIT, ExtINT = 7 };
17 enum Dest_mode { Physical, Logical };
18 enum Polarity { High_active, Low_active };
19 enum Trigger { Edge, Level };
22 Io_apic_entry(Unsigned8 vector, Delivery d, Dest_mode dm, Polarity p,
23 Trigger t, Unsigned8 dest)
24 : _e(vector | (d << 8) | (dm << 11) | (p << 13) | (t << 15) | (1<<16)
25 | (((Unsigned64)dest) << 56))
28 unsigned delivery() const { return (_e >> 8) & 7; }
29 void delivery(unsigned m) { _e = (_e & ~(7 << 8)) | ((m & 7) << 8); }
30 unsigned dest_mode() const { return _e & (1 << 11); }
31 void dest_mode(bool p) { _e = (_e & ~(1<<11)) | ((unsigned long)p << 11); }
32 unsigned dest() const { return _e >> 56; }
33 void dest(unsigned d) { _e = (_e & ~(0xffULL << 56)) | ((Unsigned64)d << 56); }
34 unsigned mask() const { return _e & (1U << 16); }
35 void mask(bool m) { _e = (_e & ~(1ULL << 16)) | ((Unsigned64)m << 16); }
36 unsigned trigger() const { return _e & (1 << 15); }
37 unsigned polarity() const { return _e & (1 << 13); }
38 unsigned vector() const { return _e & 0xff; }
39 void vector(Unsigned8 v) { _e = (_e & ~0xff) | v; }
40 void trigger(Mword tr) { _e = (_e & ~(1UL << 15)) | ((tr & 1) << 15); }
41 void polarity(Mword pl) { _e = (_e & ~(1UL << 13)) | ((pl & 1) << 13); }
42 } __attribute__((packed));
48 enum { Max_ioapics = 6 };
53 Unsigned32 volatile adr;
55 Unsigned32 volatile data;
56 } __attribute__((packed));
62 static Io_apic _apics[Max_ioapics];
63 static unsigned _nr_irqs;
64 static Acpi_madt const *_madt;
73 #include "lock_guard.h"
75 Io_apic Io_apic::_apics[Io_apic::Max_ioapics];
76 Acpi_madt const *Io_apic::_madt;
77 unsigned Io_apic::_nr_irqs;
80 PRIVATE inline NEEDS["lock_guard.h"]
82 Io_apic::read(int reg)
84 Lock_guard<typeof(_l)> g(&_l);
86 asm volatile ("": : :"memory");
90 PRIVATE inline NEEDS["lock_guard.h"]
92 Io_apic::modify(int reg, Mword set_bits, Mword del_bits)
95 Lock_guard<typeof(_l)> g(&_l);
97 asm volatile ("": : :"memory");
104 PRIVATE inline NEEDS["lock_guard.h"]
106 Io_apic::write(int reg, Mword value)
108 Lock_guard<typeof(_l)> g(&_l);
110 asm volatile ("": : :"memory");
116 Io_apic::num_entries()
118 return (read(1) >> 16) & 0xff;
122 PUBLIC inline NEEDS["kdb_ke.h"]
124 Io_apic::read_entry(unsigned i)
127 //assert_kdb(i <= num_entries());
128 e._e = (Unsigned64)read(0x10+2*i) | (((Unsigned64)read(0x11+2*i)) << 32);
133 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::write]
135 Io_apic::write_entry(unsigned i, Io_apic_entry const &e)
137 //assert_kdb(i <= num_entries());
138 write(0x10+2*i, e._e);
139 write(0x11+2*i, e._e >> 32);
142 PUBLIC static FIASCO_INIT
146 _madt = Acpi::find<Acpi_madt const *>("APIC");
150 printf("Could not find APIC in RSDT nor XSDT, skipping init\n");
153 printf("IO-APIC: MADT = %p\n", _madt);
158 Acpi_madt::Io_apic const *ioapic = static_cast<Acpi_madt::Io_apic const *>(_madt->find(Acpi_madt::IOAPIC, n_apics));
162 if (n_apics >= Max_ioapics)
164 printf("Maximum number of IO-APICs exceeded ignore further IO-APICs\n");
168 printf("IO-APIC[%2d]: struct: %p adr=%x\n", n_apics, ioapic, ioapic->adr);
171 Address va = Mem_layout::alloc_io_vmem(Config::PAGE_SIZE);
174 Kmem::map_phys_page(ioapic->adr, va, false, true, &offs);
176 Kip::k()->add_mem_region(Mem_desc(ioapic->adr, ioapic->adr + Config::PAGE_SIZE -1, Mem_desc::Reserved));
179 Io_apic *apic = Io_apic::apic(n_apics);
180 apic->_apic = (Io_apic::Apic*)(va + offs);
182 unsigned ne = apic->num_entries();
183 apic->_offset = _nr_irqs;
186 for (unsigned i = 0; i <= ne; ++i)
189 Io_apic_entry e(v, Io_apic_entry::Fixed, Io_apic_entry::Physical,
190 Io_apic_entry::High_active, Io_apic_entry::Edge, 0);
191 apic->write_entry(i, e);
194 printf("IO-APIC[%2d]: pins %u\n", n_apics, ne);
200 printf("IO-APIC: Could not find IO-APIC in MADT, skip init\n");
205 printf("IO-APIC: dual 8259: %s\n", _madt->apic_flags & 1 ? "yes" : "no");
207 for (unsigned tmp = 0;;++tmp)
209 Acpi_madt::Irq_source const *irq
210 = static_cast<Acpi_madt::Irq_source const *>(_madt->find(Acpi_madt::Irq_src_ovr, tmp));
215 printf("IO-APIC: ovr[%2u] %02x -> %x\n", tmp, irq->src, irq->irq);
223 Io_apic::total_irqs()
228 Io_apic::legacy_override(unsigned i)
236 Acpi_madt::Irq_source const *irq
237 = static_cast<Acpi_madt::Irq_source const *>(_madt->find(Acpi_madt::Irq_src_ovr, tmp));
252 unsigned ne = num_entries();
253 for (unsigned i = 0; i <= ne; ++i)
255 Io_apic_entry e = read_entry(i);
256 printf(" PIN[%2u%c]: vector=%2x, del=%u, dm=%s, dest=%u (%s, %s)\n",
257 i, e.mask() ? 'm' : '.',
258 e.vector(), e.delivery(), e.dest_mode() ? "logical" : "physical",
260 e.polarity() ? "low" : "high",
261 e.trigger() ? "level" : "edge");
269 { return _apics[0]._apic; }
273 Io_apic::valid() const { return _apic; }
275 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::modify]
277 Io_apic::mask(unsigned irq)
279 //assert_kdb(irq <= _apic->num_entries());
280 modify(0x10 + irq * 2, 1UL << 16, 0);
283 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::modify]
285 Io_apic::unmask(unsigned irq)
287 //assert_kdb(irq <= _apic->num_entries());
288 modify(0x10 + irq * 2, 0, 1UL << 16);
291 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::read]
293 Io_apic::masked(unsigned irq)
295 //assert_kdb(irq <= _apic->num_entries());
296 return read(0x10 + irq * 2) & (1UL << 16);
299 PUBLIC inline NEEDS[Io_apic::read]
306 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::modify]
308 Io_apic::set_dest(unsigned irq, Mword dst)
310 //assert_kdb(irq <= _apic->num_entries());
311 modify(0x11 + irq * 2, dst & (~0UL << 24), ~0UL << 24);
314 PUBLIC inline NEEDS[Io_apic::num_entries]
317 { return num_entries() + 1; }
321 Io_apic::gsi_offset() const { return _offset; }
325 Io_apic::apic(unsigned idx)
326 { return &_apics[idx]; }
330 Io_apic::find_apic(unsigned irqnum)
332 for (unsigned i = Max_ioapics; i > 0; --i)
334 if (_apics[i-1]._apic && _apics[i-1]._offset < irqnum)