]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/io_apic.cpp
update
[l4.git] / kernel / fiasco / src / kern / io_apic.cpp
1 INTERFACE:
2
3 #include <types.h>
4 #include "initcalls.h"
5 #include <spin_lock.h>
6
7 class Acpi_madt;
8
9 class Io_apic_entry
10 {
11   friend class Io_apic;
12 private:
13   Unsigned64 _e;
14
15 public:
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 };
20
21   Io_apic_entry() {}
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))
26   {}
27
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));
43
44
45 class Io_apic
46 {
47 public:
48   enum { Max_ioapics = 6 };
49
50 private:
51   struct Apic
52   {
53     Unsigned32 volatile adr;
54     Unsigned32 dummy[3];
55     Unsigned32 volatile data;
56   } __attribute__((packed));
57
58   Apic *_apic;
59   Spin_lock<> _l;
60   unsigned _offset;
61
62   static Io_apic _apics[Max_ioapics];
63   static unsigned _nr_irqs;
64   static Acpi_madt const *_madt;
65 };
66
67 IMPLEMENTATION:
68
69 #include "acpi.h"
70 #include "kmem.h"
71 #include "kdb_ke.h"
72 #include "kip.h"
73 #include "lock_guard.h"
74
75 Io_apic Io_apic::_apics[Io_apic::Max_ioapics];
76 Acpi_madt const *Io_apic::_madt;
77 unsigned Io_apic::_nr_irqs;
78
79
80 PRIVATE inline NEEDS["lock_guard.h"]
81 Mword
82 Io_apic::read(int reg)
83 {
84   Lock_guard<typeof(_l)> g(&_l);
85   _apic->adr = reg;
86   asm volatile ("": : :"memory");
87   return _apic->data;
88 }
89
90 PRIVATE inline NEEDS["lock_guard.h"]
91 void
92 Io_apic::modify(int reg, Mword set_bits, Mword del_bits)
93 {
94   register Mword tmp;
95   Lock_guard<typeof(_l)> g(&_l);
96   _apic->adr = reg;
97   asm volatile ("": : :"memory");
98   tmp = _apic->data;
99   tmp &= ~del_bits;
100   tmp |= set_bits;
101   _apic->data = tmp;
102 }
103
104 PRIVATE inline NEEDS["lock_guard.h"]
105 void
106 Io_apic::write(int reg, Mword value)
107 {
108   Lock_guard<typeof(_l)> g(&_l);
109   _apic->adr = reg;
110   asm volatile ("": : :"memory");
111   _apic->data = value;
112 }
113
114 PRIVATE inline
115 unsigned
116 Io_apic::num_entries()
117 {
118   return (read(1) >> 16) & 0xff;
119 }
120
121
122 PUBLIC inline NEEDS["kdb_ke.h"]
123 Io_apic_entry
124 Io_apic::read_entry(unsigned i)
125 {
126   Io_apic_entry e;
127   //assert_kdb(i <= num_entries());
128   e._e = (Unsigned64)read(0x10+2*i) | (((Unsigned64)read(0x11+2*i)) << 32);
129   return e;
130 }
131
132
133 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::write]
134 void
135 Io_apic::write_entry(unsigned i, Io_apic_entry const &e)
136 {
137   //assert_kdb(i <= num_entries());
138   write(0x10+2*i, e._e);
139   write(0x11+2*i, e._e >> 32);
140 }
141
142 PUBLIC static FIASCO_INIT
143 bool
144 Io_apic::init()
145 {
146   _madt = Acpi::find<Acpi_madt const *>("APIC");
147
148   if (_madt == 0)
149     {
150       printf("Could not find APIC in RSDT nor XSDT, skipping init\n");
151       return false;
152     }
153   printf("IO-APIC: MADT = %p\n", _madt);
154
155   int n_apics = 0;
156
157   for (n_apics = 0;
158        Acpi_madt::Io_apic const *ioapic = static_cast<Acpi_madt::Io_apic const *>(_madt->find(Acpi_madt::IOAPIC, n_apics));
159        ++n_apics)
160     {
161
162       if (n_apics >= Max_ioapics)
163         {
164           printf("Maximum number of IO-APICs exceeded ignore further IO-APICs\n");
165           break;
166         }
167
168       printf("IO-APIC[%2d]: struct: %p adr=%x\n", n_apics, ioapic, ioapic->adr);
169
170       Address offs;
171       Address va = Mem_layout::alloc_io_vmem(Config::PAGE_SIZE);
172       assert (va);
173
174       Kmem::map_phys_page(ioapic->adr, va, false, true, &offs);
175
176       Kip::k()->add_mem_region(Mem_desc(ioapic->adr, ioapic->adr + Config::PAGE_SIZE -1, Mem_desc::Reserved));
177
178
179       Io_apic *apic = Io_apic::apic(n_apics);
180       apic->_apic = (Io_apic::Apic*)(va + offs);
181       apic->write(0, 0);
182       unsigned ne = apic->num_entries();
183       apic->_offset = _nr_irqs;
184       _nr_irqs += ne + 1;
185
186       for (unsigned i = 0; i <= ne; ++i)
187         {
188           int v = 0x20+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);
192         }
193
194       printf("IO-APIC[%2d]: pins %u\n", n_apics, ne);
195       apic->dump();
196     }
197
198   if (!n_apics)
199     {
200       printf("IO-APIC: Could not find IO-APIC in MADT, skip init\n");
201       return false;
202     }
203
204
205   printf("IO-APIC: dual 8259: %s\n", _madt->apic_flags & 1 ? "yes" : "no");
206
207   for (unsigned tmp = 0;;++tmp)
208     {
209       Acpi_madt::Irq_source const *irq
210         = static_cast<Acpi_madt::Irq_source const *>(_madt->find(Acpi_madt::Irq_src_ovr, tmp));
211
212       if (!irq)
213         break;
214
215       printf("IO-APIC: ovr[%2u] %02x -> %x\n", tmp, irq->src, irq->irq);
216     }
217
218   return true;
219 };
220
221 PUBLIC static
222 unsigned
223 Io_apic::total_irqs()
224 { return _nr_irqs; }
225
226 PUBLIC static 
227 unsigned
228 Io_apic::legacy_override(unsigned i)
229 {
230   if (!_madt)
231     return i;
232
233   unsigned tmp = 0;
234   for (;;++tmp)
235     {
236       Acpi_madt::Irq_source const *irq
237         = static_cast<Acpi_madt::Irq_source const *>(_madt->find(Acpi_madt::Irq_src_ovr, tmp));
238
239       if (!irq)
240         break;
241
242       if (irq->src == i)
243         return irq->irq;
244     }
245   return i;
246 }
247
248 PUBLIC
249 void
250 Io_apic::dump()
251 {
252   unsigned ne = num_entries();
253   for (unsigned i = 0; i <= ne; ++i)
254     {
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",
259              e.dest(),
260              e.polarity() ? "low" : "high",
261              e.trigger() ? "level" : "edge");
262     }
263
264 }
265
266 PUBLIC static inline
267 bool
268 Io_apic::active()
269 { return _apics[0]._apic; }
270
271 PUBLIC inline
272 bool
273 Io_apic::valid() const { return _apic; }
274
275 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::modify]
276 void
277 Io_apic::mask(unsigned irq)
278 {
279   //assert_kdb(irq <= _apic->num_entries());
280   modify(0x10 + irq * 2, 1UL << 16, 0);
281 }
282
283 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::modify]
284 void
285 Io_apic::unmask(unsigned irq)
286 {
287   //assert_kdb(irq <= _apic->num_entries());
288   modify(0x10 + irq * 2, 0, 1UL << 16);
289 }
290
291 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::read]
292 bool
293 Io_apic::masked(unsigned irq)
294 {
295   //assert_kdb(irq <= _apic->num_entries());
296   return read(0x10 + irq * 2) & (1UL << 16);
297 }
298
299 PUBLIC inline NEEDS[Io_apic::read]
300 void
301 Io_apic::sync()
302 {
303   (void)_apic->data;
304 }
305
306 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::modify]
307 void
308 Io_apic::set_dest(unsigned irq, Mword dst)
309 {
310   //assert_kdb(irq <= _apic->num_entries());
311   modify(0x11 + irq * 2, dst & (~0UL << 24), ~0UL << 24);
312 }
313
314 PUBLIC inline NEEDS[Io_apic::num_entries]
315 unsigned
316 Io_apic::nr_irqs()
317 { return num_entries() + 1; }
318
319 PUBLIC inline
320 unsigned
321 Io_apic::gsi_offset() const { return _offset; }
322
323 PUBLIC static inline
324 Io_apic *
325 Io_apic::apic(unsigned idx)
326 { return &_apics[idx]; }
327
328 PUBLIC static
329 unsigned
330 Io_apic::find_apic(unsigned irqnum)
331 {
332   for (unsigned i = Max_ioapics; i > 0; --i)
333     {
334       if (_apics[i-1]._apic && _apics[i-1]._offset < irqnum)
335         return i - 1;
336     }
337   return 0;
338 };
339