My Project
Loading...
Searching...
No Matches
acpi.c
Go to the documentation of this file.
1/*
2 * PROJECT: MatanelOS Kernel
3 * LICENSE: GPLv3
4 * PURPOSE: ACPI Parsing & Implementation.
5 * DEVELOPER: https://github.com/slep2-0
6 */
7
8#include "../../includes/mh.h"
9#include "../../includes/mg.h"
10#include "../../includes/efi.h"
11
12static bool validate_acpi_chksum(uint8_t* data, size_t len) {
13 uint8_t sum = 0;
14 // acpi checksums work by 8 bit addition, if it results 0, the checksum is valid.
15 for (size_t i = 0; i < len; i++) {
16 sum += data[i];
17 }
18 return sum == 0;
19}
20
22
23static void map_physical_range(uint64_t phys, size_t length, uint32_t flags) {
24 uint64_t start = phys & 0xFFFULL;
25 uint64_t end = ((phys + length) + VirtualPageSize - 1) & 0xFFFULL;
26 for (uint64_t p = start; p < end; p += VirtualPageSize) {
27 uintptr_t v = (p + PhysicalMemoryOffset);
28 PMMPTE pte = MiGetPtePointer(v);
29 MI_WRITE_PTE(pte, v, p, flags);
30 }
31}
32
33static void* MiFindACPIHeader(XSDT* xsdt, const char* headerSignature) {
34 uint32_t xsdt_len = xsdt->h.Length;
35 if (xsdt_len < sizeof(ACPI_SDT_HEADER)) return NULL;
36 uint32_t entries = (xsdt_len - sizeof(ACPI_SDT_HEADER)) / sizeof(uint64_t);
37#ifdef DEBUG
38 gop_printf(COLOR_RED, "Amount of ACPI Entries: %d\n", entries);
39#endif
40 for (uint32_t i = 0; i < entries; ++i) {
41 uint64_t headerPhys = xsdt->Entries[i];
42 map_physical_range(headerPhys, sizeof(ACPI_SDT_HEADER), PAGE_PRESENT | PAGE_RW | PAGE_PCD);
43 ACPI_SDT_HEADER* hdr = (ACPI_SDT_HEADER*)(headerPhys + PhysicalMemoryOffset);
44
45 // check signature quickly
46 if (kmemcmp(hdr->Signature, headerSignature, 4) == 0) {
47#ifdef DEBUG
48 gop_printf(COLOR_RED, "Iteration %d, signature valid.\n", i);
49#endif
50 uint32_t table_len = hdr->Length;
51 if (table_len < sizeof(ACPI_SDT_HEADER)) {
52#ifdef DEBUG
53 gop_printf(COLOR_RED, "Iteration %d, table_len < sizeof(ACPI_SDT_HEADER), continuing...\n", i);
54#endif
55 continue; // invalid length
56 }
57 // map full table
58 map_physical_range(headerPhys, table_len, PAGE_PRESENT | PAGE_RW | PAGE_PCD);
59 // validate table checksum
60 if (!validate_acpi_chksum((uint8_t*)hdr, table_len)) { gop_printf(COLOR_RED, "ACPI Checksum invalid..\n"); continue; }
61#ifdef DEBUG
62 gop_printf(COLOR_LIME, "Returning specified header at pointer %p\n", hdr);
63#endif
64 return (void*)hdr;
65 }
66#ifdef DEBUG
67 else {
68 gop_printf(COLOR_RED, "Signature for iteration %d isn't valid... Pointer (physical): %p\n", i, (void*)(uintptr_t)headerPhys);
69 }
70#endif
71 }
72#ifdef DEBUG
73 gop_printf(COLOR_RED, "Exhausted all iterations, returning NULL.\n");
74#endif
75 return NULL;
76}
77
78// Global table definitions
79FADT* fadt;
80MADT* madt;
81
82void
84 void
85)
86
87/*++
88
89 Routine description : This function cold resets the computer, it does not return. Call appropriate cleanup functions before calling this function.
90
91 Arguments:
92
93 None.
94
95 Return Values:
96
97 None.
98
99--*/
100
101{
102 if (!fadt) return;
103 if (fadt->ResetReg.Address == 0) {
104 gop_printf(COLOR_RED, "No ACPI Reset Register present.\n");
105 return;
106 }
107 uint16_t port;
108 uint64_t phys;
109 switch (fadt->ResetReg.AddressSpace) {
110 case 1: // System I/O
111 port = (uint16_t)fadt->ResetReg.Address;
112 __outbyte(port, fadt->ResetValue);
113 break;
114 case 0: // Memory mapped (MMIO)
115 phys = fadt->ResetReg.Address;
116 // Map one page containing the reset register itself.
117 PMMPTE pte = MiGetPtePointer((uintptr_t)phys);
118 MI_WRITE_PTE(pte, phys, phys, PAGE_PRESENT | PAGE_RW | PAGE_PWT | PAGE_PCD);
119 volatile uint8_t* reg = (volatile uint8_t*)phys;
120 *reg = fadt->ResetValue;
121 break;
122 default:
123 gop_printf(COLOR_RED, "Unsupported ACPI reset AddressSpace: %d\n",
124 fadt->ResetReg.AddressSpace);
125 break;
126 }
127
128}
129
130MTSTATUS MhParseLAPICs(uint8_t* buffer, size_t maxCPUs, uint32_t* cpuCount, uint32_t* lapicAddress) {
131 if (!madt) return MT_NO_RESOURCES;
132 // Deference the lapicAddress ptr and put the lapic address for each CPU there.
133 *lapicAddress = madt->lapicAddress;
134 size_t count = 0;
135 // The pointer right after the MADT table (according to the spec)
136 uint8_t* ptr = (uint8_t*)madt + sizeof(MADT);
137 // The end of pointer is the length of the whole table itself.
138 uint8_t* end = (uint8_t*)madt + madt->h.Length;
139
140 while (ptr < end && count < maxCPUs) {
141 uint8_t type = ptr[0];
142 uint8_t len = ptr[1];
143
144 if (type == MADT_LAPIC) {
145 // Found a LAPIC table.
146 MADT_LOCAL_APIC* lapic = (MADT_LOCAL_APIC*)ptr;
147 if (lapic->Flags & 1) {
148 // Enabled
149 gop_printf(COLOR_LIME, "Found a CPU with LAPIC ID %d\n", lapic->ApicId);
150 buffer[count++] = lapic->ApicId; // Store the APIC ID.
151 }
152 }
153
154 ptr += len;
155 }
156
157 if (count > 0) {
158 *cpuCount = count;
159 return MT_SUCCESS;
160 }
161 else return MT_GENERAL_FAILURE;
162}
163
165 uintptr_t rsdpPhys = boot_info_local.AcpiRsdpPhys;
166 if (!rsdpPhys) return MT_INVALID_ADDRESS;
167 map_physical_range(rsdpPhys, sizeof(RSDP_Descriptor), PAGE_PRESENT | PAGE_RW | PAGE_PCD);
168 RSDP_Descriptor* rsdp = (RSDP_Descriptor*)(rsdpPhys + PhysicalMemoryOffset);
169
170 // Validate signatures and checksums.
171 if (kmemcmp(rsdp->Signature, "RSD PTR ", 8) != 0) return (MTSTATUS)0xC000BABE;
172 if (!validate_acpi_chksum((uint8_t*)rsdp, 20)) return MT_INVALID_CHECK;
173 uint64_t xsdtPhys = 0;
174 if (rsdp->Revision >= 2 && rsdp->Length >= sizeof(RSDP_Descriptor)) {
175 // map whole RSDP length
176 map_physical_range(rsdpPhys, rsdp->Length, PAGE_PRESENT | PAGE_RW | PAGE_PCD);
177 if (!validate_acpi_chksum((uint8_t*)rsdp, rsdp->Length)) return MT_INVALID_CHECK;
178 xsdtPhys = rsdp->XsdtAddress;
179 }
180 if (!xsdtPhys) return (MTSTATUS)0xC000BEEF;
181
182 // Map XSDT header first so we can read its Length
183 map_physical_range(xsdtPhys, sizeof(ACPI_SDT_HEADER), PAGE_PRESENT | PAGE_RW | PAGE_PCD);
184 XSDT* xsdt = (XSDT*)(xsdtPhys + PhysicalMemoryOffset);
185 if (xsdt->h.Length < sizeof(ACPI_SDT_HEADER)) return MT_INVALID_STATE;
186
187 // Map the entire XSDT table
188 map_physical_range(xsdtPhys, xsdt->h.Length, PAGE_PRESENT | PAGE_RW | PAGE_PCD);
189
190 // Now find FACP (FADT) (the function checks for checksum automatically)
191 ACPI_SDT_HEADER* facp = (ACPI_SDT_HEADER*)MiFindACPIHeader(xsdt, "FACP");
192 if (!facp) return MT_NOT_FOUND;
193
194 // put in the global FADT ptr
195 fadt = (FADT*)facp;
196
197 // Find MADT
198 ACPI_SDT_HEADER* madtACPI = (ACPI_SDT_HEADER*)MiFindACPIHeader(xsdt, "APIC");
199 if (!madtACPI) return MT_NOT_FOUND;
200
201 madt = (MADT*)madtACPI;
202
203 return MT_SUCCESS;
204}
205
FADT * fadt
Definition acpi.c:79
void MhRebootComputer(void)
Definition acpi.c:83
BOOT_INFO boot_info_local
Definition kernel.c:27
MTSTATUS MhParseLAPICs(uint8_t *buffer, size_t maxCPUs, uint32_t *cpuCount, uint32_t *lapicAddress)
Definition acpi.c:130
MADT * madt
Definition acpi.c:80
MTSTATUS MhInitializeACPI(void)
Definition acpi.c:164
struct _BOOT_INFO BOOT_INFO
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:694
FORCEINLINE void __outbyte(unsigned short port, unsigned char val)
Definition intrin.h:179
PMMPTE MiGetPtePointer(IN uintptr_t va)
Definition map.c:76
#define COLOR_LIME
Definition mg.h:44
#define COLOR_RED
Colors definitions for easier access.
Definition mg.h:29
uint32_t flags
Definition mh.h:2
@ MADT_LAPIC
Definition mh.h:102
uint32_t lapicAddress
Definition mh.h:1
@ PAGE_RW
Definition mm.h:272
@ PAGE_PWT
Definition mm.h:280
@ PAGE_PRESENT
Definition mm.h:268
@ PAGE_PCD
Definition mm.h:285
FORCEINLINE int kmemcmp(const void *s1, const void *s2, size_t n)
Definition mm.h:566
struct _MMPTE * PMMPTE
#define PhysicalMemoryOffset
Definition mm.h:56
#define VirtualPageSize
Definition mm.h:53
#define MI_WRITE_PTE(_PtePointer, _Va, _Pa, _Flags)
Definition mm.h:90
#define MT_SUCCESS
Definition mtstatus.h:22
#define MT_GENERAL_FAILURE
Definition mtstatus.h:31
#define MT_INVALID_STATE
Definition mtstatus.h:25
#define MT_INVALID_ADDRESS
Definition mtstatus.h:46
int32_t MTSTATUS
Definition mtstatus.h:12
#define MT_NOT_FOUND
Definition mtstatus.h:30
#define MT_NO_RESOURCES
Definition mtstatus.h:32
#define MT_INVALID_CHECK
Definition mtstatus.h:33