]> rtime.felk.cvut.cz Git - l4.git/blobdiff - kernel/fiasco/src/kern/acpi.cpp
Inital import
[l4.git] / kernel / fiasco / src / kern / acpi.cpp
diff --git a/kernel/fiasco/src/kern/acpi.cpp b/kernel/fiasco/src/kern/acpi.cpp
new file mode 100644 (file)
index 0000000..a3915cc
--- /dev/null
@@ -0,0 +1,305 @@
+INTERFACE:
+
+#include <types.h>
+
+class Acpi_gas
+{
+public:
+  enum Type { System_mem = 0, System_io = 1, Pci_cfg_mem = 2 };
+  Unsigned8  id;
+  Unsigned8  width;
+  Unsigned8  offset;
+  Unsigned8  access_size;
+  Unsigned64 addr;
+} __attribute__((packed));
+
+
+
+class Acpi_table_head
+{
+public:
+  char       signature[4];
+  Unsigned32 len;
+  Unsigned8  rev;
+  Unsigned8  chk_sum;
+  char       oem_id[6];
+  char       oem_tid[8];
+  Unsigned32 oem_rev;
+  Unsigned32 creator_id;
+  Unsigned32 creator_rev;
+
+  bool checksum_ok() const;
+} __attribute__((packed));
+
+
+template< typename T >
+class Acpi_sdt : public Acpi_table_head
+{
+public:
+  T ptrs[0];
+
+} __attribute__((packed));
+
+typedef Acpi_sdt<Unsigned32> Acpi_rsdt;
+typedef Acpi_sdt<Unsigned64> Acpi_xsdt;
+
+class Acpi_rsdp
+{
+public:
+  char       signature[8];
+  Unsigned8  chk_sum;
+  char       oem[6];
+  Unsigned8  rev;
+  Unsigned32 rsdt_phys;
+  Unsigned32 len;
+  Unsigned64 xsdt_phys;
+  Unsigned8  ext_chk_sum;
+  char       reserved[3];
+
+  Acpi_rsdt const *rsdt() const;
+  Acpi_xsdt const *xsdt() const;
+
+  bool checksum_ok() const;
+
+  static Acpi_rsdp const *locate();
+} __attribute__((packed));
+
+class Acpi
+{
+public:
+  static Acpi_rsdt const *rsdt() { return _rsdt; }
+  static Acpi_xsdt const *xsdt() { return _xsdt; }
+
+private:
+  static Acpi_rsdt const *_rsdt;
+  static Acpi_xsdt const *_xsdt;
+  static bool _init_done;
+};
+
+class Acpi_madt : public Acpi_table_head
+{
+public:
+  enum Type
+  { LAPIC, IOAPIC, Irq_src_ovr, NMI, LAPIC_NMI, LAPIC_adr_ovr, IOSAPIC,
+    LSAPIC, Irq_src };
+
+  struct Apic_head
+  {
+    Unsigned8 type;
+    Unsigned8 len;
+  } __attribute__((packed));
+
+  struct Io_apic : public Apic_head
+  {
+    Unsigned8 id;
+    Unsigned8 res;
+    Unsigned32 adr;
+    Unsigned32 irq_base;
+  } __attribute__((packed));
+
+  struct Irq_source : public Apic_head
+  {
+    Unsigned8  bus;
+    Unsigned8  src;
+    Unsigned32 irq;
+    Unsigned16 flags;
+  } __attribute__((packed));
+
+public:
+  Unsigned32 local_apic;
+  Unsigned32 apic_flags;
+
+private:
+  char data[0];
+} __attribute__((packed));
+
+
+IMPLEMENTATION:
+
+#include "kmem.h"
+
+Acpi_rsdt const *Acpi::_rsdt;
+Acpi_xsdt const *Acpi::_xsdt;
+bool Acpi::_init_done;
+
+PUBLIC static
+void
+Acpi::init_virt()
+{
+  if (_init_done)
+    return;
+  _init_done = 1;
+
+  printf("ACPI-Init\n");
+
+  Acpi_rsdp const *rsdp = Acpi_rsdp::locate();
+  if (!rsdp)
+    {
+      printf("ACPI: Could not find RSDP, skip init\n");
+      return;
+    }
+
+  printf("ACPI: RSDP = %p   pRSDT = %08x   pXSDT = %16llx\n",
+         rsdp, rsdp->rsdt_phys, rsdp->xsdt_phys);
+  printf("ACPI: OEM: %c%c%c%c%c%c\n",
+         rsdp->oem[0], rsdp->oem[1], rsdp->oem[2],
+         rsdp->oem[3], rsdp->oem[4], rsdp->oem[5]);
+
+  if (rsdp->rev && rsdp->xsdt_phys)
+    {
+      Acpi_xsdt const *x = Kmem::dev_map.map((const Acpi_xsdt *)rsdp->xsdt_phys);
+      if (x == (Acpi_xsdt const *)~0UL)
+        printf("ACPI: Could not map XSDT\n");
+      else if (!x->checksum_ok())
+        printf("ACPI: Checksum mismatch in XSDT\n");
+      else
+        _xsdt = x;
+    }
+
+  if (rsdp->rsdt_phys)
+    {
+      Acpi_rsdt const *r = Kmem::dev_map.map((const Acpi_rsdt *)rsdp->rsdt_phys);
+      if (r == (Acpi_rsdt const *)~0UL)
+        printf("ACPI: Could not map RSDT\n");
+      else if (!r->checksum_ok())
+        printf("ACPI: Checksum mismatch in RSDT\n");
+      else
+        _rsdt = r;
+    }
+}
+
+PUBLIC static
+template< typename T >
+T
+Acpi::find(const char *s)
+{
+  T a = 0;
+  init_virt();
+  if (_xsdt)
+    a = static_cast<T>(_xsdt->find(s));
+  else if (_rsdt)
+    a = static_cast<T>(_rsdt->find(s));
+  return a;
+}
+
+IMPLEMENT
+Acpi_rsdt const *
+Acpi_rsdp::rsdt() const
+{
+  return (Acpi_rsdt const*)rsdt_phys;
+}
+
+IMPLEMENT
+Acpi_xsdt const *
+Acpi_rsdp::xsdt() const
+{
+  if (rev == 0)
+    return 0;
+  return (Acpi_xsdt const*)xsdt_phys;
+}
+
+IMPLEMENT
+bool
+Acpi_rsdp::checksum_ok() const
+{
+  // ACPI 1.0 checksum
+  Unsigned8 sum = 0;
+  for (unsigned i = 0; i < 20; i++)
+    sum += *((Unsigned8 *)this + i);
+
+  if (sum)
+    return false;
+
+  if (rev == 0)
+    return true;
+
+  // Extended Checksum
+  for (unsigned i = 0; i < len && i < 4096; ++i)
+    sum += *((Unsigned8 *)this + i);
+
+  return !sum;
+}
+
+IMPLEMENT
+bool
+Acpi_table_head::checksum_ok() const
+{
+  Unsigned8 sum = 0;
+  for (unsigned i = 0; i < len && i < 4096; ++i)
+    sum += *((Unsigned8 *)this + i);
+
+  return !sum;
+}
+
+PUBLIC
+template< typename T >
+Acpi_table_head const *
+Acpi_sdt<T>::find(char const sig[4]) const
+{
+  for (unsigned i = 0; i < ((len-sizeof(Acpi_table_head))/sizeof(ptrs[0])); ++i)
+    {
+      Acpi_table_head const *t = Kmem::dev_map.lookup((Acpi_table_head const*)ptrs[i]);
+      if (t == (Acpi_table_head const *)~0UL)
+       continue;
+
+      if (t->signature[0] == sig[0]
+         && t->signature[1] == sig[1]
+         && t->signature[2] == sig[2]
+         && t->signature[3] == sig[3]
+          && t->checksum_ok())
+       return t;
+    }
+
+  return 0;
+}
+
+PUBLIC
+Acpi_madt::Apic_head const *
+Acpi_madt::find(Unsigned8 type, int idx) const
+{
+  for (unsigned i = 0; i < len-sizeof(Acpi_madt);)
+    {
+      Apic_head const *a = (Apic_head const *)(data + i);
+      //printf("a=%p, a->type=%u, a->len=%u\n", a, a->type, a->len);
+      if (a->type == type)
+       {
+         if (!idx)
+           return a;
+         --idx;
+       }
+      i += a->len;
+    }
+
+  return 0;
+}
+
+// ------------------------------------------------------------------------
+IMPLEMENTATION [ia32,amd64]:
+
+IMPLEMENT
+Acpi_rsdp const *
+Acpi_rsdp::locate()
+{
+  enum
+  {
+    ACPI20_PC99_RSDP_START = 0x0e0000,
+    ACPI20_PC99_RSDP_END =   0x100000
+  };
+
+  for (Address p = ACPI20_PC99_RSDP_START; p < ACPI20_PC99_RSDP_END; p += 16)
+    {
+      Acpi_rsdp const* r = (Acpi_rsdp const *)p;
+      if (r->signature[0] == 'R' &&
+         r->signature[1] == 'S' &&
+         r->signature[2] == 'D' &&
+         r->signature[3] == ' ' &&
+         r->signature[4] == 'P' &&
+         r->signature[5] == 'T' &&
+         r->signature[6] == 'R' &&
+         r->signature[7] == ' ' &&
+          r->checksum_ok())
+       return r;
+    }
+
+  return 0;
+}