1#pragma once
2
3#include <uacpi/types.h>
4#include <uacpi/status.h>
5
6#ifdef __cplusplus
7extern "C" {
8#endif
9
10// Forward-declared to avoid including the entire acpi.h here
11struct acpi_fadt;
12struct acpi_entry_hdr;
13struct acpi_sdt_hdr;
14
15typedef struct uacpi_table_identifiers {
16 uacpi_object_name signature;
17
18 // if oemid[0] == 0 this field is ignored
19 char oemid[6];
20
21 // if oem_table_id[0] == 0 this field is ignored
22 char oem_table_id[8];
23} uacpi_table_identifiers;
24
25typedef struct uacpi_table {
26 union {
27 uacpi_virt_addr virt_addr;
28 void *ptr;
29 struct acpi_sdt_hdr *hdr;
30 };
31
32 // Index number used to identify this table internally
33 uacpi_size index;
34} uacpi_table;
35
36/**
37 * Returns the number of tables stored in the internal array via 'out_count'.
38 * This includes all firmware-provided, dynamically loaded, as well as
39 * client-installed tables via 'uacpi_table_install' etc.
40 */
41uacpi_size uacpi_table_count(void);
42
43/**
44 * Install a table from either a virtual or a physical address.
45 * The table is simply stored in the internal table array, and not loaded by
46 * the interpreter (see uacpi_table_load).
47 *
48 * The table is optionally returned via 'out_table'.
49 *
50 * Manual calls to uacpi_table_install are not subject to filtering via the
51 * table installation callback (if any).
52 */
53uacpi_status uacpi_table_install(
54 void*, uacpi_table *out_table
55);
56uacpi_status uacpi_table_install_physical(
57 uacpi_phys_addr, uacpi_table *out_table
58);
59
60#ifndef UACPI_BAREBONES_MODE
61/**
62 * Load a previously installed table by feeding it to the interpreter.
63 */
64uacpi_status uacpi_table_load(uacpi_size index);
65#endif // !UACPI_BAREBONES_MODE
66
67/**
68 * Helpers for finding tables.
69 *
70 * for find_by_signature:
71 * 'signature' is an array of 4 characters, a null terminator is not
72 * necessary and can be omitted (especially useful for non-C language
73 * bindings)
74 *
75 * for find_by_signature_at:
76 * 'offset' specifies the base index in the internal array where to start
77 * searching for the table
78 *
79 * for find_nth_by_signature:
80 * This works exactly like find_by_signature, but finds the nth copy of the
81 * specified table in the firmware enumeration order
82 *
83 * 'out_table' is a pointer to a caller allocated uacpi_table structure that
84 * receives the table pointer & its internal index in case the call was
85 * successful.
86 *
87 * NOTE:
88 * The returned table's reference count is incremented by 1, which keeps its
89 * mapping alive forever unless uacpi_table_unref() is called for this table
90 * later on. Calling uacpi_table_find_next_with_same_signature() on a table also
91 * drops its reference count by 1, so if you want to keep it mapped you must
92 * manually call uacpi_table_ref() beforehand.
93 */
94uacpi_status uacpi_table_find_by_signature(
95 const uacpi_char *signature, uacpi_table *out_table
96);
97uacpi_status uacpi_table_find_by_signature_at(
98 const uacpi_char *signature, uacpi_size offset, uacpi_table *out_table
99);
100uacpi_status uacpi_table_find_nth_by_signature(
101 const uacpi_char *signature, uacpi_size nth, uacpi_table *out_table
102);
103
104uacpi_status uacpi_table_find_next_with_same_signature(
105 uacpi_table *in_out_table
106);
107uacpi_status uacpi_table_find(
108 const uacpi_table_identifiers *id, uacpi_table *out_table
109);
110
111/**
112 * Returns a table by its index in the internal table array.
113 *
114 * The number of available tables can be queried via 'uacpi_table_count()'.
115 *
116 * NOTE:
117 * Even if a table is present, this may still fail with
118 * UACPI_STATUS_BAD_CHECKSUM in case UACPI_FLAG_BAD_CSUM_FATAL is enabled.
119 */
120uacpi_status uacpi_table_get_by_index(uacpi_size, uacpi_table *out_table);
121
122/**
123 * Increment/decrement a table's reference count.
124 * The table is unmapped when the reference count drops to 0.
125 */
126uacpi_status uacpi_table_ref(uacpi_table*);
127uacpi_status uacpi_table_ref_by_index(uacpi_size);
128uacpi_status uacpi_table_unref(uacpi_table*);
129uacpi_status uacpi_table_unref_by_index(uacpi_size);
130
131/**
132 * Returns the pointer to a sanitized internal version of FADT.
133 *
134 * The revision is guaranteed to be correct. All of the registers are converted
135 * to GAS format. Fields that might contain garbage are cleared.
136 */
137uacpi_status uacpi_table_fadt(struct acpi_fadt**);
138
139typedef enum uacpi_table_installation_disposition {
140 // Allow the table to be installed as-is
141 UACPI_TABLE_INSTALLATION_DISPOSITON_ALLOW = 0,
142
143 /**
144 * Deny the table from being installed completely. This is useful for
145 * debugging various problems, e.g. AML loading bad SSDTs that cause the
146 * system to hang or enter an undesired state.
147 */
148 UACPI_TABLE_INSTALLATION_DISPOSITON_DENY,
149
150 /**
151 * Override the table being installed with the table at the virtual address
152 * returned in 'out_override_address'.
153 */
154 UACPI_TABLE_INSTALLATION_DISPOSITON_VIRTUAL_OVERRIDE,
155
156 /**
157 * Override the table being installed with the table at the physical address
158 * returned in 'out_override_address'.
159 */
160 UACPI_TABLE_INSTALLATION_DISPOSITON_PHYSICAL_OVERRIDE,
161} uacpi_table_installation_disposition;
162
163typedef uacpi_table_installation_disposition (*uacpi_table_installation_handler)
164 (struct acpi_sdt_hdr *hdr, uacpi_u64 *out_override_address);
165
166/**
167 * Set a handler that is invoked for each table before it gets installed.
168 *
169 * Depending on the return value, the table is either allowed to be installed
170 * as-is, denied, or overriden with a new one.
171 */
172uacpi_status uacpi_set_table_installation_handler(
173 uacpi_table_installation_handler handler
174);
175
176typedef enum uacpi_table_origin {
177 /**
178 * A table that originated from a physical address provided by the firmware.
179 * All tables discovered via RSDP have this origin.
180 */
181 UACPI_TABLE_ORIGIN_FIRMWARE_PHYSICAL = 1 << 0,
182
183 /**
184 * A table that was dynamically loaded by the AML firmware.
185 * This includes both Load/LoadTable opcodes. Such tables live in a
186 * heap-allocated kernel buffer.
187 */
188 UACPI_TABLE_ORIGIN_FIRMWARE_VIRTUAL = 1 << 1,
189
190 /**
191 * A table installed by the client code via uacpi_table_install_physical().
192 */
193 UACPI_TABLE_ORIGIN_HOST_PHYSICAL = 1 << 2,
194
195 /**
196 * A table installed by the client code via uacpi_table_install().
197 */
198 UACPI_TABLE_ORIGIN_HOST_VIRTUAL = 1 << 3,
199} uacpi_table_origin;
200
201typedef struct uacpi_table_info {
202 /**
203 * The index of this table in the internal array
204 */
205 uacpi_size idx;
206
207 /**
208 * Size of this table in bytes
209 */
210 uacpi_size size;
211
212 union {
213 /**
214 * The physical address of this table, only applicable for
215 * UACPI_TABLE_ORIGIN_*_PHYSICAL.
216 */
217 uacpi_phys_addr phys_addr;
218
219 /**
220 * The virtual address of this table, only applicable for
221 * UACPI_TABLE_ORIGIN_*_VIRTUAL.
222 *
223 * NOTE: use uacpi_table_get_by_index() if you need a virtual address
224 * for a UACPI_TABLE_ORIGIN_*_PHYSICAL table in order to map it.
225 */
226 void *virt_addr;
227 };
228
229 /**
230 * Signature of this table
231 */
232 uacpi_char signature[4];
233
234 /**
235 * One of 'uacpi_table_origin' values
236 */
237 uacpi_u8 origin;
238
239/**
240 * This table has been processed & loaded by the AML interpreter.
241 * Only applicable for AML bytecode tables.
242 */
243#define UACPI_TABLE_LOADED (1 << 0)
244
245/**
246 * This table's checksum has been checked. The checksum is valid if
247 * UACPI_TABLE_CSUM_BAD is not set.
248 */
249#define UACPI_TABLE_CSUM_CHECKED (1 << 1)
250
251/**
252 * This table's checksum was found to be incorrect.
253 * Note that if UACPI_FLAG_PROACTIVE_TBL_CSUM is enabled alongside
254 * UACPI_FLAG_BAD_CSUM_FATAL, such tables are never installed in the first
255 * place.
256 */
257#define UACPI_TABLE_CSUM_BAD (1 << 2)
258
259 /**
260 * A mask of UACPI_TABLE_* flags
261 */
262 uacpi_u8 flags;
263
264 /**
265 * Reference count of this table
266 */
267 uacpi_u16 reference_count;
268} uacpi_table_info;
269
270typedef uacpi_iteration_decision (*uacpi_table_iteration_callback)
271 (uacpi_handle, uacpi_table_info *info);
272
273/**
274 * Iterate every installed table on the system.
275 *
276 * The provided callback receives the information about each table in the
277 * 'info' pointer. A table may be mapped by client code if needed via
278 * uacpi_table_get_by_index().
279 *
280 * Note that this is a low level helper that iterates _every_ installed table,
281 * even tables that are unreachable via uacpi_table_find() etc. due to bad
282 * checksum.
283 */
284uacpi_status uacpi_for_each_table(
285 uacpi_table_iteration_callback, void *user
286);
287
288/*
289 * Retrieve information about the table installed internally at 'idx'.
290 *
291 * The number of available tables can be retrieved via uacpi_table_count().
292 */
293uacpi_status uacpi_table_info_get_by_index(
294 uacpi_size idx, uacpi_table_info *out_info
295);
296
297typedef uacpi_iteration_decision (*uacpi_subtable_iteration_callback)
298 (uacpi_handle, struct acpi_entry_hdr*);
299
300/**
301 * Iterate every subtable of a table such as MADT or SRAT.
302 *
303 * 'hdr' is the pointer to the main table, 'hdr_size' is the number of bytes in
304 * the table before the beginning of the subtable records. 'cb' is the callback
305 * invoked for each subtable with the 'user' context pointer passed for every
306 * invocation.
307 *
308 * Example usage:
309 * uacpi_table tbl;
310 *
311 * uacpi_table_find_by_signature(ACPI_MADT_SIGNATURE, &tbl);
312 * uacpi_for_each_subtable(
313 * tbl.hdr, sizeof(struct acpi_madt), parse_madt, NULL
314 * );
315 */
316uacpi_status uacpi_for_each_subtable(
317 struct acpi_sdt_hdr *hdr, size_t hdr_size,
318 uacpi_subtable_iteration_callback cb, void *user
319);
320
321#ifdef __cplusplus
322}
323#endif
324