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