PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
tables.c
Go to the documentation of this file.
3
4#include <kernel/fs/file.h>
5#include <kernel/fs/sysfs.h>
6#include <kernel/fs/vfs.h>
7#include <kernel/log/log.h>
8#include <kernel/log/panic.h>
9#include <kernel/acpi/acpi.h>
10
11#include <boot/boot_info.h>
12
13#include <errno.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17
21
23
24static uint64_t acpi_table_read(file_t* file, void* buffer, size_t count, size_t* offset)
25{
26 if (file == NULL || buffer == NULL || offset == NULL)
27 {
28 errno = EINVAL;
29 return ERR;
30 }
31
32 sdt_header_t* table = file->vnode->data;
33 if (table == NULL)
34 {
35 errno = EINVAL;
36 return ERR;
37 }
38
39 return BUFFER_READ(buffer, count, offset, table, table->length);
40}
41
45
47{
48 if (table->length < sizeof(sdt_header_t))
49 {
50 LOG_ERR("table too small (%u bytes)\n", table->length);
51 return false;
52 }
53
54 if (!acpi_is_checksum_valid(table, table->length))
55 {
56 LOG_ERR("invalid checksum for table %.*s\n", SDT_SIGNATURE_LENGTH, table->signature);
57 return false;
58 }
59
60 return true;
61}
62
63static bool acpi_is_xsdt_valid(xsdt_t* xsdt)
64{
65 if (!acpi_is_table_valid(&xsdt->header))
66 {
67 return false;
68 }
69
70 if (memcmp(xsdt->header.signature, "XSDT", SDT_SIGNATURE_LENGTH) != 0)
71 {
72 LOG_ERR("invalid XSDT signature\n");
73 return false;
74 }
75
76 return true;
77}
78
79static bool acpi_is_rsdp_valid(rsdp_t* rsdp)
80{
81 LOG_DEBUG("validating RSDP at [%p-%p]\n", rsdp, (void*)((uintptr_t)rsdp + rsdp->length));
82
83 if (memcmp(rsdp->signature, "RSD PTR ", RSDP_SIGNATURE_LENGTH) != 0)
84 {
85 LOG_ERR("invalid RSDP signature\n");
86 return false;
87 }
88
90 {
91 LOG_ERR("invalid RSDP checksum\n");
92 return false;
93 }
94
96 {
97 LOG_ERR("unsupported ACPI revision %u\n", rsdp->revision);
98 return false;
99 }
100
101 if (!acpi_is_checksum_valid(rsdp, rsdp->length))
102 {
103 LOG_ERR("invalid extended RSDP checksum\n");
104 return false;
105 }
106
107 return true;
108}
109
111{
112 if (!acpi_is_table_valid(table))
113 {
114 LOG_ERR("invalid table %.*s\n", SDT_SIGNATURE_LENGTH, table->signature);
115 return ERR;
116 }
117
118 sdt_header_t* cachedTable = malloc(table->length);
119 if (cachedTable == NULL)
120 {
121 LOG_ERR("failed to allocate memory for ACPI table\n");
122 return ERR;
123 }
124 memcpy(cachedTable, table, table->length);
125
127 if (cachedTables == NULL)
128 {
129 LOG_ERR("failed to allocate memory for ACPI table cache\n");
130 free(cachedTable);
131 return ERR;
132 }
133 cachedTables[tableAmount++].table = cachedTable;
134
135 LOG_INFO("%.*s %p 0x%06x v%02X %.*s\n", SDT_SIGNATURE_LENGTH, cachedTable->signature, cachedTable,
136 cachedTable->length, cachedTable->revision, SDT_OEM_ID_LENGTH, cachedTable->oemId);
137 return 0;
138}
139
141{
142 if (!acpi_is_xsdt_valid(xsdt))
143 {
144 return ERR;
145 }
146
147 uint64_t amountOfTablesInXsdt = (xsdt->header.length - sizeof(sdt_header_t)) / sizeof(sdt_header_t*);
148 for (uint64_t i = 0; i < amountOfTablesInXsdt; i++)
149 {
151 if (acpi_tables_push(table) == ERR)
152 {
153 LOG_ERR("failed to cache table %.4s\n", table->signature);
154 return ERR;
155 }
156 }
157
158 return 0;
159}
160
162{
164 if (fadt == NULL)
165 {
166 LOG_ERR("failed to find FACP table\n");
167 return ERR;
168 }
169
170 if (fadt->dsdt == 0 && fadt->xDsdt == 0)
171 {
172 LOG_ERR("FADT has no DSDT pointer\n");
173 return ERR;
174 }
175
176 if (fadt->dsdt == 0)
177 {
178 if (acpi_tables_push((void*)PML_ENSURE_HIGHER_HALF(fadt->xDsdt)) == ERR)
179 {
180 LOG_ERR("failed to cache DSDT table from fadt_t::xDsdt\n");
181 return ERR;
182 }
183 }
184
185 if (acpi_tables_push((void*)PML_ENSURE_HIGHER_HALF(fadt->dsdt)) == ERR)
186 {
187 LOG_ERR("failed to cache DSDT table from fadt_t::dsdt\n");
188 return ERR;
189 }
190
191 return 0;
192}
193
195{
196 if (!acpi_is_rsdp_valid(rsdp))
197 {
198 LOG_ERR("invalid RSDP provided to ACPI tables init\n");
199 return ERR;
200 }
201
203 LOG_INFO("located XSDT at %p\n", rsdp->xsdtAddress);
204
205 if (acpi_tables_load_from_xsdt(xsdt) == ERR)
206 {
207 LOG_ERR("failed to load ACPI tables from XSDT\n");
208 return ERR;
209 }
210
212 {
213 LOG_ERR("failed to load ACPI tables from FADT\n");
214 return ERR;
215 }
216
217 return 0;
218}
219
221{
222 dentry_t* acpiRoot = acpi_get_dir();
223 assert(acpiRoot != NULL);
224 UNREF_DEFER(acpiRoot);
225
226 tablesDir = sysfs_dir_new(acpiRoot, "tables", NULL, NULL);
227 if (tablesDir == NULL)
228 {
229 LOG_ERR("failed to create ACPI tables sysfs directory");
230 return ERR;
231 }
232
233 for (uint64_t i = 0; i < tableAmount; i++)
234 {
235 sdt_header_t* table = cachedTables[i].table;
236
237 char name[SDT_SIGNATURE_LENGTH + 2];
238 if (memcmp(table->signature, "SSDT", SDT_SIGNATURE_LENGTH) == 0)
239 {
240 snprintf(name, MAX_PATH, "%.4s%llu", table->signature, ssdtAmount++);
241 }
242 else
243 {
245 name[SDT_SIGNATURE_LENGTH] = '\0';
246 }
247
249 if (cachedTables[i].file == NULL)
250 {
251 LOG_ERR("failed to create ACPI table sysfs file for %.*s", SDT_SIGNATURE_LENGTH, table->signature);
252 return ERR;
253 }
254 }
255
256 return 0;
257}
258
259sdt_header_t* acpi_tables_lookup(const char* signature, uint64_t minSize, uint64_t n)
260{
261 if (signature == NULL || strlen(signature) != SDT_SIGNATURE_LENGTH)
262 {
263 errno = EINVAL;
264 return NULL;
265 }
266
267 uint64_t depth = 0;
268 for (uint64_t i = 0; i < tableAmount; i++)
269 {
270 if (memcmp(cachedTables[i].table->signature, signature, SDT_SIGNATURE_LENGTH) == 0)
271 {
272 if (depth++ == n)
273 {
274 if (cachedTables[i].table->length < minSize)
275 {
276 errno = EILSEQ;
277 return NULL;
278 }
279
280 return cachedTables[i].table;
281 }
282 }
283 }
284
285 if (depth != 0)
286 {
287 errno = ERANGE;
288 }
289 else
290 {
291 errno = ENOENT;
292 }
293 return NULL;
294}
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
#define assert(expression)
Definition assert.h:29
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
#define FADT_SIGNATURE
FADT table signature.
Definition tables.h:103
uint64_t acpi_tables_init(rsdp_t *rsdp)
Initialize ACPI tables and call their init handlers.
Definition tables.c:194
sdt_header_t * acpi_tables_lookup(const char *signature, uint64_t minSize, uint64_t n)
Lookup the n'th table matching the signature.
Definition tables.c:259
uint64_t acpi_tables_expose(void)
Expose ACPI tables to devfs.
Definition tables.c:220
#define RSDP_CURRENT_REVISION
The expected value of the revision field in the RSDP structure.
Definition acpi.h:66
#define SDT_OEM_ID_LENGTH
The length of the OEM ID field in the SDT header structure.
Definition acpi.h:76
#define RSDP_V1_LENGTH
Length of the RSDP structure for ACPI version 1.0.
Definition acpi.h:129
bool acpi_is_checksum_valid(void *table, uint64_t length)
Check if the sum of all bytes in a table is 0.
Definition acpi.c:30
#define SDT_SIGNATURE_LENGTH
The length of the signature field in the SDT header structure.
Definition acpi.h:71
#define RSDP_SIGNATURE_LENGTH
Length of the signature field in the RSDP structure.
Definition acpi.h:105
dentry_t * acpi_get_dir(void)
Retrieve the devfs root directory for ACPI.
Definition acpi.c:41
dentry_t * sysfs_file_new(dentry_t *parent, const char *name, const vnode_ops_t *vnodeOps, const file_ops_t *fileOps, void *data)
Create a new file inside a mounted sysfs instance.
Definition sysfs.c:153
dentry_t * sysfs_dir_new(dentry_t *parent, const char *name, const vnode_ops_t *vnodeOps, void *data)
Create a new directory inside a mounted sysfs instance.
Definition sysfs.c:114
#define LOG_ERR(format,...)
Definition log.h:93
#define LOG_INFO(format,...)
Definition log.h:91
#define LOG_DEBUG(format,...)
Definition log.h:85
#define PML_ENSURE_HIGHER_HALF(addr)
Ensures that the given address is in the higher half of the address space.
#define UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:122
#define BUFFER_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:209
#define ENOENT
No such file or directory.
Definition errno.h:42
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ERANGE
Math result not representable.
Definition errno.h:202
#define errno
Error number variable.
Definition errno.h:27
#define EILSEQ
Illegal byte sequence.
Definition errno.h:447
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
static uint64_t offset
Definition screen.c:19
static atomic_long count
Definition main.c:11
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_PUBLIC void * realloc(void *ptr, size_t size)
Definition realloc.c:13
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC int memcmp(const void *s1, const void *s2, size_t n)
Definition memcmp.c:3
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:61
_PUBLIC size_t strlen(const char *s)
Definition strlen.c:3
Cached ACPI table.
Definition tables.h:247
sdt_header_t * table
Definition tables.h:248
dentry_t * file
The devfs file representing the table.
Definition tables.h:249
Directory entry structure.
Definition dentry.h:155
Fixed ACPI Description Table.
Definition tables.h:45
uint64_t xDsdt
Extended pointer to dsdt, should be used if dsdt is 0.
Definition tables.h:89
uint32_t dsdt
Definition tables.h:48
File operations structure.
Definition file.h:54
size_t(* read)(file_t *file, void *buffer, size_t count, size_t *offset)
Definition file.h:58
File structure.
Definition file.h:39
vnode_t * vnode
Definition file.h:43
Root System Description Pointer.
Definition acpi.h:114
char signature[RSDP_SIGNATURE_LENGTH]
Definition acpi.h:115
uint8_t revision
Definition acpi.h:118
uint32_t length
Definition acpi.h:120
uint64_t xsdtAddress
Definition acpi.h:121
System Description Table Header.
Definition acpi.h:90
uint8_t revision
Definition acpi.h:93
uint32_t length
Definition acpi.h:92
uint8_t oemId[SDT_OEM_ID_LENGTH]
Definition acpi.h:95
uint8_t signature[SDT_SIGNATURE_LENGTH]
Definition acpi.h:91
void * data
Filesystem defined data.
Definition vnode.h:52
Extended System Description Table.
Definition acpi.h:138
sdt_header_t header
Definition acpi.h:139
sdt_header_t * tables[]
Definition acpi.h:140
static bool acpi_is_xsdt_valid(xsdt_t *xsdt)
Definition tables.c:63
static uint64_t acpi_tables_push(sdt_header_t *table)
Definition tables.c:110
static uint64_t acpi_tables_load_from_fadt(void)
Definition tables.c:161
static uint64_t ssdtAmount
Definition tables.c:18
static uint64_t tableAmount
Definition tables.c:19
static dentry_t * tablesDir
Definition tables.c:22
static acpi_cached_table_t * cachedTables
Definition tables.c:20
static file_ops_t tableFileOps
Definition tables.c:42
static bool acpi_is_table_valid(sdt_header_t *table)
Definition tables.c:46
static bool acpi_is_rsdp_valid(rsdp_t *rsdp)
Definition tables.c:79
static uint64_t acpi_table_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition tables.c:24
static uint64_t acpi_tables_load_from_xsdt(xsdt_t *xsdt)
Definition tables.c:140