]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/acpi.cpp
Update
[l4.git] / kernel / fiasco / src / kern / acpi.cpp
1 INTERFACE:
2
3 #include <types.h>
4
5 class Acpi_gas
6 {
7 public:
8   enum Type { System_mem = 0, System_io = 1, Pci_cfg_mem = 2 };
9   Unsigned8  id;
10   Unsigned8  width;
11   Unsigned8  offset;
12   Unsigned8  access_size;
13   Unsigned64 addr;
14 } __attribute__((packed));
15
16
17
18 class Acpi_table_head
19 {
20 public:
21   char       signature[4];
22   Unsigned32 len;
23   Unsigned8  rev;
24   Unsigned8  chk_sum;
25   char       oem_id[6];
26   char       oem_tid[8];
27   Unsigned32 oem_rev;
28   Unsigned32 creator_id;
29   Unsigned32 creator_rev;
30
31   bool checksum_ok() const;
32 } __attribute__((packed));
33
34
35 class Acpi_sdt
36 {
37 private:
38   unsigned _num_tables;
39   Acpi_table_head const **_tables;
40 };
41
42 class Acpi
43 {
44 public:
45   static Acpi_sdt const *sdt() { return &_sdt; }
46
47 private:
48   static Acpi_sdt _sdt;
49   static bool _init_done;
50 };
51
52 class Acpi_madt : public Acpi_table_head
53 {
54 public:
55   enum Type
56   { LAPIC, IOAPIC, Irq_src_ovr, NMI, LAPIC_NMI, LAPIC_adr_ovr, IOSAPIC,
57     LSAPIC, Irq_src };
58
59   struct Apic_head
60   {
61     Unsigned8 type;
62     Unsigned8 len;
63   } __attribute__((packed));
64
65   struct Io_apic : public Apic_head
66   {
67     enum { ID = IOAPIC };
68     Unsigned8 id;
69     Unsigned8 res;
70     Unsigned32 adr;
71     Unsigned32 irq_base;
72   } __attribute__((packed));
73
74   struct Irq_source : public Apic_head
75   {
76     enum { ID = Irq_src_ovr };
77     Unsigned8  bus;
78     Unsigned8  src;
79     Unsigned32 irq;
80     Unsigned16 flags;
81   } __attribute__((packed));
82
83 public:
84   Unsigned32 local_apic;
85   Unsigned32 apic_flags;
86
87 private:
88   char data[0];
89 } __attribute__((packed));
90
91 template< bool >
92 struct Acpi_helper_get_msb
93 { template<typename P> static Address msb(P) { return 0; } };
94
95 template<>
96 struct Acpi_helper_get_msb<true>
97 { template<typename P> static Address msb(P p) { return p >> (sizeof(Address) * 8); } };
98
99
100 IMPLEMENTATION:
101
102 #include "boot_alloc.h"
103 #include "kmem.h"
104 #include "warn.h"
105 #include <cctype>
106
107 Acpi_sdt Acpi::_sdt;
108 bool Acpi::_init_done;
109
110 template< typename T >
111 class Acpi_sdt_p : public Acpi_table_head
112 {
113 public:
114   T ptrs[0];
115
116 } __attribute__((packed));
117
118 typedef Acpi_sdt_p<Unsigned32> Acpi_rsdt_p;
119 typedef Acpi_sdt_p<Unsigned64> Acpi_xsdt_p;
120
121 class Acpi_rsdp
122 {
123 public:
124   char       signature[8];
125   Unsigned8  chk_sum;
126   char       oem[6];
127   Unsigned8  rev;
128   Unsigned32 rsdt_phys;
129   Unsigned32 len;
130   Unsigned64 xsdt_phys;
131   Unsigned8  ext_chk_sum;
132   char       reserved[3];
133
134   Acpi_rsdt_p const *rsdt() const;
135   Acpi_xsdt_p const *xsdt() const;
136
137   bool checksum_ok() const;
138
139   static Acpi_rsdp const *locate();
140 } __attribute__((packed));
141
142
143 static void
144 print_acpi_id(char const *id, int len)
145 {
146   char ID[len];
147   for (int i = 0; i < len; ++i)
148     ID[i] = isalnum(id[i]) ? id[i] : '.';
149   printf("%.*s", len, ID);
150 }
151
152 PUBLIC void
153 Acpi_rsdp::print_info() const
154 {
155   printf("ACPI: RSDP[%p]\tr%02x OEM:", this, (unsigned)rev);
156   print_acpi_id(oem, 6);
157   printf("\n");
158 }
159
160 PUBLIC void
161 Acpi_table_head::print_info() const
162 {
163   printf("ACPI: ");
164   print_acpi_id(signature, 4);
165   printf("[%p]\tr%02x OEM:", this, (unsigned)rev);
166   print_acpi_id(oem_id, 6);
167   printf(" OEMTID:");
168   print_acpi_id(oem_tid, 8);
169   printf("\n");
170 }
171
172 PUBLIC
173 void
174 Acpi_sdt::print_summary() const
175 {
176   for (unsigned i = 0; i < _num_tables; ++i)
177     if (_tables[i])
178       _tables[i]->print_info();
179 }
180
181 PUBLIC template< typename T >
182 unsigned
183 Acpi_sdt_p<T>::entries() const
184 { return (len - sizeof(Acpi_table_head)) / sizeof(ptrs[0]); }
185
186 PUBLIC template< typename SDT >
187 void
188 Acpi_sdt::init(SDT *sdt)
189 {
190   unsigned entries = sdt->entries();
191   _tables = (Acpi_table_head const **)Boot_alloced::alloc(sizeof(*_tables) * entries);
192   if (_tables)
193     {
194       _num_tables = entries;
195       for (unsigned i = 0; i < entries; ++i)
196         if (sdt->ptrs[i])
197           _tables[i] = this->map_entry(i, sdt->ptrs[i]);
198         else
199           _tables[i] = 0;
200     }
201 }
202
203 PRIVATE static
204 void *
205 Acpi::_map_table_head(Unsigned64 phys)
206 {
207   // is the acpi address bigger that our handled physical addresses
208   if (Acpi_helper_get_msb<(sizeof(phys) > sizeof(Address))>::msb(phys))
209     {
210       printf("ACPI: cannot map phys address %llx, out of range (%ubit)\n",
211              (unsigned long long)phys, (unsigned)sizeof(Address) * 8);
212       return 0;
213     }
214
215   void *t = Kmem::dev_map.map((void*)phys);
216   if (t == (void *)~0UL)
217     {
218       printf("ACPI: cannot map phys address %llx, map failed\n",
219              (unsigned long long)phys);
220       return 0;
221     }
222
223   return t;
224 }
225
226 PUBLIC static
227 bool
228 Acpi::check_signature(char const *sig, char const *reference)
229 {
230   for (; *reference; ++sig, ++reference)
231     if (*reference != *sig)
232       return false;
233
234   return true;
235 }
236
237 PUBLIC static template<typename TAB>
238 TAB *
239 Acpi::map_table_head(Unsigned64 phys)
240 { return reinterpret_cast<TAB *>(_map_table_head(phys)); }
241
242
243 PRIVATE template< typename T >
244 Acpi_table_head const *
245 Acpi_sdt::map_entry(unsigned idx, T phys)
246 {
247   if (idx >= _num_tables)
248     {
249       printf("ACPI: table index out of range (%u >= %u)\n", idx, _num_tables);
250       return 0;
251     }
252
253   return Acpi::map_table_head<Acpi_table_head>((Unsigned64)phys);
254 }
255
256
257
258 PUBLIC static
259 void
260 Acpi::init_virt()
261 {
262   enum { Print_info = 0 };
263
264   if (_init_done)
265     return;
266   _init_done = 1;
267
268   if (Print_info)
269     printf("ACPI-Init\n");
270
271   Acpi_rsdp const *rsdp = Acpi_rsdp::locate();
272   if (!rsdp)
273     {
274       WARN("ACPI: Could not find RSDP, skip init\n");
275       return;
276     }
277
278   rsdp->print_info();
279
280   if (rsdp->rev && rsdp->xsdt_phys)
281     {
282       Acpi_xsdt_p const *x = Kmem::dev_map.map((const Acpi_xsdt_p *)rsdp->xsdt_phys);
283       if (x == (Acpi_xsdt_p const *)~0UL)
284         WARN("ACPI: Could not map XSDT\n");
285       else if (!x->checksum_ok())
286         WARN("ACPI: Checksum mismatch in XSDT\n");
287       else
288         {
289           _sdt.init(x);
290           if (Print_info)
291             {
292               x->print_info();
293               _sdt.print_summary();
294             }
295           return;
296         }
297     }
298
299   if (rsdp->rsdt_phys)
300     {
301       Acpi_rsdt_p const *r = Kmem::dev_map.map((const Acpi_rsdt_p *)(unsigned long)rsdp->rsdt_phys);
302       if (r == (Acpi_rsdt_p const *)~0UL)
303         WARN("ACPI: Could not map RSDT\n");
304       else if (!r->checksum_ok())
305         WARN("ACPI: Checksum mismatch in RSDT\n");
306       else
307         {
308           _sdt.init(r);
309           if (Print_info)
310             {
311               r->print_info();
312               _sdt.print_summary();
313             }
314           return;
315         }
316     }
317 }
318
319 PUBLIC static
320 template< typename T >
321 T
322 Acpi::find(const char *s)
323 {
324   init_virt();
325   return static_cast<T>(sdt()->find(s));
326 }
327
328 IMPLEMENT
329 Acpi_rsdt_p const *
330 Acpi_rsdp::rsdt() const
331 {
332   return (Acpi_rsdt_p const*)(unsigned long)rsdt_phys;
333 }
334
335 IMPLEMENT
336 Acpi_xsdt_p const *
337 Acpi_rsdp::xsdt() const
338 {
339   if (rev == 0)
340     return 0;
341   return (Acpi_xsdt_p const*)xsdt_phys;
342 }
343
344 IMPLEMENT
345 bool
346 Acpi_rsdp::checksum_ok() const
347 {
348   // ACPI 1.0 checksum
349   Unsigned8 sum = 0;
350   for (unsigned i = 0; i < 20; i++)
351     sum += *((Unsigned8 *)this + i);
352
353   if (sum)
354     return false;
355
356   if (rev == 0)
357     return true;
358
359   // Extended Checksum
360   for (unsigned i = 0; i < len && i < 4096; ++i)
361     sum += *((Unsigned8 *)this + i);
362
363   return !sum;
364 }
365
366 IMPLEMENT
367 bool
368 Acpi_table_head::checksum_ok() const
369 {
370   Unsigned8 sum = 0;
371   for (unsigned i = 0; i < len && i < 4096; ++i)
372     sum += *((Unsigned8 *)this + i);
373
374   return !sum;
375 }
376
377 PUBLIC
378 Acpi_table_head const *
379 Acpi_sdt::find(char const *sig) const
380 {
381   for (unsigned i = 0; i < _num_tables; ++i)
382     {
383       Acpi_table_head const *t = _tables[i];
384       if (!t)
385         continue;
386
387       if (Acpi::check_signature(t->signature, sig)
388           && t->checksum_ok())
389         return t;
390     }
391
392   return 0;
393 }
394
395 PUBLIC
396 template< typename T >
397 Acpi_table_head const *
398 Acpi_sdt_p<T>::find(char const *sig) const
399 {
400   for (unsigned i = 0; i < ((len-sizeof(Acpi_table_head))/sizeof(ptrs[0])); ++i)
401     {
402       Acpi_table_head const *t = Kmem::dev_map.map((Acpi_table_head const*)ptrs[i]);
403       if (t == (Acpi_table_head const *)~0UL)
404         continue;
405
406       if (Acpi::check_signature(t->signature, sig)
407           && t->checksum_ok())
408         return t;
409     }
410
411   return 0;
412 }
413
414 PUBLIC
415 Acpi_madt::Apic_head const *
416 Acpi_madt::find(Unsigned8 type, int idx) const
417 {
418   for (unsigned i = 0; i < len-sizeof(Acpi_madt);)
419     {
420       Apic_head const *a = (Apic_head const *)(data + i);
421       //printf("a=%p, a->type=%u, a->len=%u\n", a, a->type, a->len);
422       if (a->type == type)
423         {
424           if (!idx)
425             return a;
426           --idx;
427         }
428       i += a->len;
429     }
430
431   return 0;
432 }
433
434 PUBLIC template<typename T> inline
435 T const *
436 Acpi_madt::find(int idx) const
437 {
438   return static_cast<T const *>(find(T::ID, idx));
439 }
440
441
442 // ------------------------------------------------------------------------
443 IMPLEMENTATION [ia32,amd64]:
444
445 PRIVATE static
446 Acpi_rsdp const *
447 Acpi_rsdp::locate_in_region(Address start, Address end)
448 {
449   for (Address p = start; p < end; p += 16)
450     {
451       Acpi_rsdp const* r = (Acpi_rsdp const *)p;
452       if (Acpi::check_signature(r->signature, "RSD PTR ")
453           && r->checksum_ok())
454         return r;
455     }
456
457   return 0;
458 }
459
460 IMPLEMENT
461 Acpi_rsdp const *
462 Acpi_rsdp::locate()
463 {
464   enum
465   {
466     ACPI20_PC99_RSDP_START = 0x0e0000,
467     ACPI20_PC99_RSDP_END   = 0x100000,
468
469     BDA_EBDA_SEGMENT       = 0x00040E,
470   };
471
472   // If we are booted from UEFI, bootstrap reads the RDSP pointer from
473   // UEFI and creates a memory descriptor with sub type 5 for it
474   for (auto const &md: Kip::k()->mem_descs_a())
475     if (   md.type() == Mem_desc::Info
476         && md.ext_type() == Mem_desc::Info_acpi_rsdp)
477       {
478         Acpi_rsdp const *r = Acpi::map_table_head<Acpi_rsdp>(md.start());
479         if (   Acpi::check_signature(r->signature, "RSD PTR ")
480             && r->checksum_ok())
481           return r;
482         else
483           panic("RSDP memory descriptor from bootstrap invalid");
484       }
485
486   if (Acpi_rsdp const *r = locate_in_region(ACPI20_PC99_RSDP_START,
487                                             ACPI20_PC99_RSDP_END))
488     return r;
489
490   Address ebda = *(Unsigned16 *)BDA_EBDA_SEGMENT << 4;
491   if (Acpi_rsdp const *r = locate_in_region(ebda, ebda + 1024))
492     return r;
493
494   return 0;
495 }