PatchworkOS
Loading...
Searching...
No Matches
tables.c
Go to the documentation of this file.
2
3#include <kernel/acpi/acpi.h>
4#include <kernel/fs/file.h>
5#include <kernel/fs/vfs.h>
6#include <kernel/log/log.h>
7#include <kernel/log/panic.h>
8
9#include <boot/boot_info.h>
10
11#include <errno.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15
19
21
22// Defined in the linker script
25
27{
28 if (file == NULL || buffer == NULL || offset == NULL)
29 {
30 errno = EINVAL;
31 return ERR;
32 }
33
34 sdt_header_t* table = file->inode->private;
35 if (table == NULL)
36 {
37 errno = EINVAL;
38 return ERR;
39 }
40
41 return BUFFER_READ(buffer, count, offset, table, table->length);
42}
43
47
49{
50 if (table->length < sizeof(sdt_header_t))
51 {
52 LOG_ERR("table too small (%u bytes)\n", table->length);
53 return false;
54 }
55
56 if (!acpi_is_checksum_valid(table, table->length))
57 {
58 LOG_ERR("invalid checksum for table %.*s\n", SDT_SIGNATURE_LENGTH, table->signature);
59 return false;
60 }
61
62 return true;
63}
64
65static bool acpi_is_xsdt_valid(xsdt_t* xsdt)
66{
67 if (!acpi_is_table_valid(&xsdt->header))
68 {
69 return false;
70 }
71
72 if (memcmp(xsdt->header.signature, "XSDT", SDT_SIGNATURE_LENGTH) != 0)
73 {
74 LOG_ERR("invalid XSDT signature\n");
75 return false;
76 }
77
78 return true;
79}
80
81static bool acpi_is_rsdp_valid(rsdp_t* rsdp)
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
95 if (!acpi_is_checksum_valid(rsdp, rsdp->length))
96 {
97 LOG_ERR("invalid extended RSDP checksum\n");
98 return false;
99 }
100
101 if (rsdp->revision != RSDP_CURRENT_REVISION)
102 {
103 LOG_ERR("unsupported ACPI revision %u\n", rsdp->revision);
104 }
105
106 if (!acpi_is_checksum_valid(rsdp, rsdp->length))
107 {
108 LOG_ERR("invalid extended RSDP checksum\n");
109 return false;
110 }
111
112 return true;
113}
114
116{
117 if (!acpi_is_table_valid(table))
118 {
119 LOG_ERR("invalid table %.*s\n", SDT_SIGNATURE_LENGTH, table->signature);
120 return ERR;
121 }
122
123 sdt_header_t* cachedTable = malloc(table->length);
124 if (cachedTable == NULL)
125 {
126 LOG_ERR("failed to allocate memory for ACPI table\n");
127 return ERR;
128 }
129 memcpy(cachedTable, table, table->length);
130
132 if (cachedTables == NULL)
133 {
134 LOG_ERR("failed to allocate memory for ACPI table cache\n");
135 free(cachedTable);
136 return ERR;
137 }
138 cachedTables[tableAmount++].table = cachedTable;
139
140 LOG_INFO("%.*s 0x%016lx 0x%06x v%02X %.*s\n", SDT_SIGNATURE_LENGTH, cachedTable->signature, cachedTable,
141 cachedTable->length, cachedTable->revision, SDT_OEM_ID_LENGTH, cachedTable->oemId);
142 return 0;
143}
144
146{
147 if (!acpi_is_xsdt_valid(xsdt))
148 {
149 return ERR;
150 }
151
152 uint64_t amountOfTablesInXsdt = (xsdt->header.length - sizeof(sdt_header_t)) / sizeof(sdt_header_t*);
153 for (uint64_t i = 0; i < amountOfTablesInXsdt; i++)
154 {
155 sdt_header_t* table = xsdt->tables[i];
156 if (acpi_tables_push(table) == ERR)
157 {
158 LOG_ERR("failed to cache table %.4s\n", table->signature);
159 return ERR;
160 }
161 }
162
163 return 0;
164}
165
167{
168 fadt_t* facp = FADT_GET();
169 if (facp == NULL)
170 {
171 LOG_ERR("failed to find FACP table\n");
172 return ERR;
173 }
174
175 if (acpi_tables_push((void*)facp->xDsdt) == ERR)
176 {
177 LOG_ERR("failed to cache DSDT table\n");
178 return ERR;
179 }
180
181 return 0;
182}
183
185{
186 for (const acpi_sdt_handler_t* handler = _acpiSdtHandlersStart; handler < _acpiSdtHandlersEnd; handler++)
187 {
188 if (memcmp(table->signature, handler->signature, SDT_SIGNATURE_LENGTH) == 0)
189 {
190 if (handler->init(table) == ERR)
191 {
192 LOG_ERR("failed to initialize ACPI table %.4s\n", table->signature);
193 return ERR;
194 }
195 }
196 }
197
198 return 0;
199}
200
202{
203 if (!acpi_is_rsdp_valid(rsdp))
204 {
205 panic(NULL, "invalid RSDP structure\n");
206 }
207
209 LOG_INFO("located XSDT at 0x%016lx\n", rsdp->xsdtAddress);
210
211 if (acpi_tables_load_from_xsdt(xsdt) == ERR)
212 {
213 panic(NULL, "failed to load ACPI tables from XSDT\n");
214 }
215
217 {
218 panic(NULL, "failed to load ACPI tables from FADT\n");
219 }
220
221 for (uint64_t i = 0; i < tableAmount; i++)
222 {
223 sdt_header_t* table = cachedTables[i].table;
224 if (acpi_tables_init_handlers(table) == ERR)
225 {
226 panic(NULL, "failed to initialize ACPI table %.4s\n", table->signature);
227 }
228 }
229}
230
232{
233 dentry_t* acpiRoot = acpi_get_sysfs_root();
234 assert(acpiRoot != NULL);
235 DEREF_DEFER(acpiRoot);
236
237 tablesDir = sysfs_dir_new(acpiRoot, "tables", NULL, NULL);
238 if (tablesDir == NULL)
239 {
240 panic(NULL, "failed to create ACPI tables sysfs directory");
241 }
242
243 for (uint64_t i = 0; i < tableAmount; i++)
244 {
245 sdt_header_t* table = cachedTables[i].table;
246
247 char name[SDT_SIGNATURE_LENGTH + 2];
248 if (memcmp(table->signature, "SSDT", SDT_SIGNATURE_LENGTH) == 0)
249 {
250 snprintf(name, MAX_PATH, "%.4s%llu", table->signature, ssdtAmount++);
251 }
252 else
253 {
255 name[SDT_SIGNATURE_LENGTH] = '\0';
256 }
257
259 if (cachedTables[i].file == NULL)
260 {
261 panic(NULL, "failed to create ACPI table sysfs file for %.*s", SDT_SIGNATURE_LENGTH, table->signature);
262 }
263 }
264}
265
266sdt_header_t* acpi_tables_lookup(const char* signature, uint64_t n)
267{
268 if (strlen(signature) != SDT_SIGNATURE_LENGTH)
269 {
270 LOG_ERR("invalid signature length\n");
271 return NULL;
272 }
273
274 for (uint64_t i = 0; i < tableAmount; i++)
275 {
276 if (memcmp(cachedTables[i].table->signature, signature, SDT_SIGNATURE_LENGTH) == 0)
277 {
278 if (n-- == 0)
279 {
280 return cachedTables[i].table;
281 }
282 }
283 }
284
285 return NULL;
286}
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
#define assert(expression)
Definition assert.h:29
#define FADT_GET()
Type safe way to get the FADT table.
Definition tables.h:105
void acpi_tables_init(rsdp_t *rsdp)
Initialize ACPI tables and call their init handlers.
Definition tables.c:201
sdt_header_t * acpi_tables_lookup(const char *signature, uint64_t n)
Lookup the n'th table matching the signature.
Definition tables.c:266
void acpi_tables_expose(void)
Expose ACPI tables to sysfs.
Definition tables.c:231
#define RSDP_CURRENT_REVISION
The expected value of the revision field in the RSDP structure.
Definition acpi.h:66
dentry_t * acpi_get_sysfs_root(void)
Retrieve the sysfs root directory for ACPI.
Definition acpi.c:28
#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:17
#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
#define BUFFER_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:372
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:362
#define LOG_ERR(format,...)
Definition log.h:89
#define LOG_INFO(format,...)
Definition log.h:87
#define PML_LOWER_TO_HIGHER(addr)
Converts an address from the lower half to the higher half.
#define DEREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:54
#define EINVAL
Invalid argument.
Definition errno.h:142
#define errno
Error number variable.
Definition errno.h:27
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static dentry_t * file
Definition log_file.c:17
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static atomic_long count
Definition main.c:9
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_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:4
_PUBLIC size_t strlen(const char *s)
Definition strlen.c:3
Cached ACPI table.
Definition tables.h:261
sdt_header_t * table
Definition tables.h:262
dentry_t * file
The sysfs file representing the table.
Definition tables.h:263
ACPI System Description Table handler.
Definition tables.h:249
Directory entry structure.
Definition dentry.h:83
inode_t * inode
Definition dentry.h:87
Fixed ACPI Description Table.
Definition tables.h:45
uint64_t xDsdt
Definition tables.h:89
File operations structure.
Definition file.h:57
uint64_t(* read)(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition file.h:61
File structure.
Definition file.h:37
void * private
Definition inode.h:66
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
Extended System Description Table.
Definition acpi.h:138
sdt_header_t header
Definition acpi.h:139
sdt_header_t * tables[]
Definition acpi.h:140
dentry_t * sysfs_dir_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, void *private)
Create a new directory inside a mounted SysFS instance.
Definition sysfs.c:174
dentry_t * sysfs_file_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, const file_ops_t *fileOps, void *private)
Create a new file inside a mounted SysFS instance.
Definition sysfs.c:216
static uint64_t acpi_table_read(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition tables.c:26
static bool acpi_is_xsdt_valid(xsdt_t *xsdt)
Definition tables.c:65
static uint64_t acpi_tables_push(sdt_header_t *table)
Definition tables.c:115
static uint64_t acpi_tables_load_from_fadt(void)
Definition tables.c:166
const acpi_sdt_handler_t _acpiSdtHandlersEnd[]
static uint64_t ssdtAmount
Definition tables.c:16
static uint64_t tableAmount
Definition tables.c:17
static dentry_t * tablesDir
Definition tables.c:20
static acpi_cached_table_t * cachedTables
Definition tables.c:18
const acpi_sdt_handler_t _acpiSdtHandlersStart[]
static file_ops_t tableFileOps
Definition tables.c:44
static bool acpi_is_table_valid(sdt_header_t *table)
Definition tables.c:48
static bool acpi_is_rsdp_valid(rsdp_t *rsdp)
Definition tables.c:81
static uint64_t acpi_tables_load_from_xsdt(xsdt_t *xsdt)
Definition tables.c:145
static uint64_t acpi_tables_init_handlers(sdt_header_t *table)
Definition tables.c:184