]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/io_apic.cpp
024c48a8b917ad57f3147071d8f67bd574b0f21c
[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 private:
48   Unsigned32 volatile adr;
49   Unsigned32 dummy[3];
50   Unsigned32 volatile data;
51
52   static Spin_lock _l;
53   static Io_apic *_apic;
54   static Acpi_madt const *_madt;
55 } __attribute__((packed));
56
57 IMPLEMENTATION:
58
59 #include "acpi.h"
60 #include "kmem.h"
61 #include "kdb_ke.h"
62 #include "kip.h"
63 #include "lock_guard.h"
64
65 Io_apic *Io_apic::_apic;
66 Spin_lock Io_apic::_l;
67 Acpi_madt const *Io_apic::_madt;
68
69
70
71 PRIVATE inline NEEDS["lock_guard.h"]
72 Mword
73 Io_apic::read(int reg)
74 {
75   Lock_guard<Spin_lock> g(&_l);
76   adr = reg;
77   asm volatile ("": : :"memory");
78   return data;
79 }
80
81 PRIVATE inline NEEDS["lock_guard.h"]
82 void
83 Io_apic::modify(int reg, Mword set_bits, Mword del_bits)
84 {
85   register Mword tmp;
86   Lock_guard<Spin_lock> g(&_l);
87   adr = reg;
88   asm volatile ("": : :"memory");
89   tmp = data;
90   tmp &= ~del_bits;
91   tmp |= set_bits;
92   data = tmp;
93 }
94
95 PRIVATE inline NEEDS["lock_guard.h"]
96 void
97 Io_apic::write(int reg, Mword value)
98 {
99   Lock_guard<Spin_lock> g(&_l);
100   adr = reg;
101   asm volatile ("": : :"memory");
102   data = value;
103 }
104
105 PRIVATE inline
106 unsigned
107 Io_apic::num_entries()
108 {
109   return (read(1) >> 16) & 0xff;
110 }
111
112
113 PUBLIC inline NEEDS["kdb_ke.h"]
114 Io_apic_entry
115 Io_apic::read_entry(unsigned i)
116 {
117   Io_apic_entry e;
118   //assert_kdb(i <= num_entries());
119   e._e = (Unsigned64)read(0x10+2*i) | (((Unsigned64)read(0x11+2*i)) << 32);
120   return e;
121 }
122
123
124 PUBLIC inline NEEDS["kdb_ke.h", Io_apic::write]
125 void
126 Io_apic::write_entry(unsigned i, Io_apic_entry const &e)
127 {
128   //assert_kdb(i <= num_entries());
129   write(0x10+2*i, e._e);
130   write(0x11+2*i, e._e >> 32);
131 }
132
133 PUBLIC static FIASCO_INIT
134 bool
135 Io_apic::init()
136 {
137   _madt = Acpi::find<Acpi_madt const *>("APIC");
138
139   if (_madt == 0)
140     {
141       printf("Could not find APIC in RSDT nor XSDT, skipping init\n");
142       return false;
143     }
144   printf("MADT = %p\n", _madt);
145
146   Acpi_madt::Io_apic const *ioapic
147     = static_cast<Acpi_madt::Io_apic const *>(_madt->find(Acpi_madt::IOAPIC, 0));
148
149   if (!ioapic)
150     {
151       printf("IO-APIC: Could not find IO-APIC in MADT, skip init\n");
152       return false;
153     }
154
155   printf("IO-APIC: struct: %p adr=%x\n", ioapic, ioapic->adr);
156   printf("IO-APIC: dual 8259: %s\n", _madt->apic_flags & 1 ? "yes" : "no");
157
158   unsigned tmp = 0;
159   for (;;++tmp)
160     {
161       Acpi_madt::Irq_source const *irq
162         = static_cast<Acpi_madt::Irq_source const *>(_madt->find(Acpi_madt::Irq_src_ovr, tmp));
163
164       if (!irq)
165         break;
166
167       printf("IO-APIC: ovr[%2u] %02x -> %x\n", tmp, irq->src, irq->irq);
168     }
169
170   if (tmp)
171     printf("IO-APIC: NOTE IRQ overrides are ignored!\n");
172
173   Address offs;
174   Kmem::map_phys_page(ioapic->adr, Mem_layout::Io_apic_page,
175                       false, true, &offs);
176
177   Kip::k()->add_mem_region(Mem_desc(ioapic->adr, ioapic->adr + Config::PAGE_SIZE -1, Mem_desc::Reserved));
178
179
180   Io_apic *apic = (Io_apic*)(Mem_layout::Io_apic_page + offs);
181   _apic = apic;
182   apic->write(0, 0);
183   unsigned ne = apic->num_entries();
184
185   for (unsigned i = 0; i <= ne; ++i)
186     {
187       int v = 0x20+i;
188       Io_apic_entry e(v, Io_apic_entry::Fixed, Io_apic_entry::Physical,
189                       Io_apic_entry::High_active, Io_apic_entry::Edge, 0);
190       apic->write_entry(i, e);
191     }
192
193   printf("IO-APIC: pins %u\n", ne);
194   dump();
195
196   return true;
197 };
198
199 PUBLIC static 
200 unsigned
201 Io_apic::legacy_override(unsigned i)
202 {
203   unsigned tmp = 0;
204   for (;;++tmp)
205     {
206       Acpi_madt::Irq_source const *irq
207         = static_cast<Acpi_madt::Irq_source const *>(_madt->find(Acpi_madt::Irq_src_ovr, tmp));
208
209       if (!irq)
210         break;
211
212       if (irq->src == i)
213         return irq->irq;
214     }
215   return i;
216 }
217
218 PUBLIC static
219 void
220 Io_apic::dump()
221 {
222   unsigned ne = _apic->num_entries();
223   for (unsigned i = 0; i <= ne; ++i)
224     {
225       Io_apic_entry e = _apic->read_entry(i);
226       printf("  PIN[%2u%c]: vector=%2x, del=%u, dm=%s, dest=%u (%s, %s)\n",
227              i, e.mask() ? 'm' : '.',
228              e.vector(), e.delivery(), e.dest_mode() ? "logical" : "physical",
229              e.dest(),
230              e.polarity() ? "low" : "high",
231              e.trigger() ? "level" : "edge");
232     }
233
234 }
235
236 PUBLIC static inline
237 bool
238 Io_apic::active()
239 { return _apic; }
240
241 PUBLIC static inline NEEDS["kdb_ke.h", Io_apic::modify]
242 void
243 Io_apic::mask(unsigned irq)
244 {
245   //assert_kdb(irq <= _apic->num_entries());
246   _apic->modify(0x10 + irq * 2, 1UL << 16, 0);
247 }
248
249 PUBLIC static inline NEEDS["kdb_ke.h", Io_apic::modify]
250 void
251 Io_apic::unmask(unsigned irq)
252 {
253   //assert_kdb(irq <= _apic->num_entries());
254   _apic->modify(0x10 + irq * 2, 0, 1UL << 16);
255 }
256
257 PUBLIC static inline NEEDS["kdb_ke.h", Io_apic::read]
258 bool
259 Io_apic::masked(unsigned irq)
260 {
261   //assert_kdb(irq <= _apic->num_entries());
262   return _apic->read(0x10 + irq * 2) & (1UL << 16);
263 }
264
265 PUBLIC static inline NEEDS[Io_apic::read]
266 void
267 Io_apic::sync()
268 {
269   (void)_apic->data;
270 }
271
272 PUBLIC static inline NEEDS["kdb_ke.h", Io_apic::modify]
273 void
274 Io_apic::set_dest(unsigned irq, Mword dst)
275 {
276   //assert_kdb(irq <= _apic->num_entries());
277   _apic->modify(0x11 + irq * 2, dst & (~0UL << 24), ~0UL << 24);
278 }
279
280 PUBLIC static inline NEEDS[Io_apic::num_entries]
281 unsigned
282 Io_apic::nr_irqs()
283 { return _apic->num_entries() + 1; }
284
285 PUBLIC static inline
286 Io_apic *
287 Io_apic::apic()
288 { return _apic; }
289