summaryrefslogtreecommitdiffhomepage
path: root/dev/kernel/src/ACPIFactoryInterface.cc
blob: 42819b7eafaebfab7d03083efb5ca2c4a69ebdd2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* ========================================

  Copyright (C) 2024-2025, Amlal El Mahrouss, licensed under the Apache 2.0 license.

======================================== */

#include <ArchKit/ArchKit.h>
#include <KernelKit/HeapMgr.h>
#include <NeKit/KString.h>
#include <modules/ACPI/ACPIFactoryInterface.h>

namespace Kernel {
constexpr STATIC const auto kMinACPIVer = 1U;

/// @brief Finds a descriptor table inside ACPI XSDT.
ErrorOr<voidPtr> ACPIFactoryInterface::Find(const Char* signature) {
  if (this->fRsdp) return ErrorOr<voidPtr>{-kErrorInvalidData};
  if (!signature) return ErrorOr<voidPtr>{-kErrorInvalidData};
  if (*signature == 0) return ErrorOr<voidPtr>{-kErrorInvalidData};

  RSDP* rsp_ptr = reinterpret_cast<RSDP*>(this->fRsdp);

  if (rsp_ptr->Revision < kMinACPIVer) return ErrorOr<voidPtr>{-kErrorInvalidData};

  RSDT* xsdt = reinterpret_cast<RSDT*>(rsp_ptr->RsdtAddress);

  Int64 num = (xsdt->Length - sizeof(SDT)) / sizeof(Int64);

  /***
    crucial to avoid underflows.
  */
  if (num < 1) {
    /// stop here, we should have entries...
    ke_panic(RUNTIME_CHECK_ACPI);
    return ErrorOr<voidPtr>{-kErrorInvalidData};
  }

  this->fEntries = num;

  (Void)(kout << "ACPI: Number of entries: " << number(this->fEntries) << kendl);
  (Void)(kout << "ACPI: Revision: " << number(xsdt->Revision) << kendl);
  (Void)(kout << "ACPI: Signature: " << xsdt->Signature << kendl);
  (Void)(kout << "ACPI: Address of XSDT: " << hex_number((UIntPtr) xsdt) << kendl);

  static constexpr const UInt16 cAcpiSignatureLength = 4U;

  for (Size index = 0; index < this->fEntries; ++index) {
    SDT* sdt = reinterpret_cast<SDT*>(xsdt->AddressArr[index]);

    (Void)(kout << "ACPI: Checksum: " << number(sdt->Checksum) << kendl);
    (Void)(kout << "ACPI: Revision: " << number(sdt->Revision) << kendl);

    for (UInt16 signature_index = 0; signature_index < cAcpiSignatureLength; ++signature_index) {
      if (sdt->Signature[signature_index] != signature[signature_index]) break;

      if (signature_index == (cAcpiSignatureLength - 1)) {
        (Void)(kout << "ACPI: SDT Signature: " << sdt->Signature << kendl);
        (Void)(kout << "ACPI: SDT OEM ID: " << sdt->OemId << kendl);
        return ErrorOr<voidPtr>(reinterpret_cast<voidPtr>(xsdt->AddressArr[index]));
      }
    }
  }

  return ErrorOr<voidPtr>{-kErrorInvalidData};
}

/***
@brief Checksum on SDT header.
@param checksum the header to checksum
@param len the length of it.
*/
bool ACPIFactoryInterface::Checksum(const Char* checksum, SSizeT len) {
  if (len == 0 || !checksum) return NO;

  Char chr = 0;

  for (SSizeT index = 0L; index < len; ++index) {
    chr += checksum[index];
  }

  return chr == 0;
}

ErrorOr<voidPtr> ACPIFactoryInterface::operator[](const Char* signature) {
  if (!signature) return ErrorOr<voidPtr>{-kErrorInvalidData};
  return this->Find(signature);
}
}  // namespace Kernel