1#pragma once
2
3#include <uacpi/types.h>
4#include <uacpi/platform/arch_helpers.h>
5
6#ifdef __cplusplus
7extern "C" {
8#endif
9
10// Returns the PHYSICAL address of the RSDP structure via *out_rsdp_address.
11uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr *out_rsdp_address);
12
13/**
14 * Map a physical memory range starting at 'addr' with length 'len', and return
15 * a virtual address that can be used to access it.
16 *
17 * NOTE: 'addr' may be misaligned, in this case the host is expected to round it
18 * down to the nearest page-aligned boundary and map that, while making
19 * sure that at least 'len' bytes are still mapped starting at 'addr'. The
20 * return value preserves the misaligned offset.
21 *
22 * Example for uacpi_kernel_map(0x1ABC, 0xF00):
23 * 1. Round down the 'addr' we got to the nearest page boundary.
24 * Considering a PAGE_SIZE of 4096 (or 0x1000), 0x1ABC rounded down
25 * is 0x1000, offset within the page is 0x1ABC - 0x1000 => 0xABC
26 * 2. Requested 'len' is 0xF00 bytes, but we just rounded the address
27 * down by 0xABC bytes, so add those on top. 0xF00 + 0xABC => 0x19BC
28 * 3. Round up the final 'len' to the nearest PAGE_SIZE boundary, in
29 * this case 0x19BC is 0x2000 bytes (2 pages if PAGE_SIZE is 4096)
30 * 4. Call the VMM to map the aligned address 0x1000 (from step 1)
31 * with length 0x2000 (from step 3). Let's assume the returned
32 * virtual address for the mapping is 0xF000.
33 * 5. Add the original offset within page 0xABC (from step 1) to the
34 * resulting virtual address 0xF000 + 0xABC => 0xFABC. Return it
35 * to uACPI.
36 */
37void *uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len);
38
39/**
40 * Unmap a virtual memory range at 'addr' with a length of 'len' bytes.
41 *
42 * NOTE: 'addr' may be misaligned, see the comment above 'uacpi_kernel_map'.
43 * Similar steps to uacpi_kernel_map can be taken to retrieve the
44 * virtual address originally returned by the VMM for this mapping
45 * as well as its true length.
46 */
47void uacpi_kernel_unmap(void *addr, uacpi_size len);
48
49#ifndef UACPI_FORMATTED_LOGGING
50void uacpi_kernel_log(uacpi_log_level, const uacpi_char*);
51#else
52UACPI_PRINTF_DECL(2, 3)
53void uacpi_kernel_log(uacpi_log_level, const uacpi_char*, ...);
54void uacpi_kernel_vlog(uacpi_log_level, const uacpi_char*, uacpi_va_list);
55#endif
56
57/**
58 * Only the above ^^^ API may be used by early table access and
59 * UACPI_BAREBONES_MODE.
60 */
61#ifndef UACPI_BAREBONES_MODE
62
63/**
64 * Convenience initialization/deinitialization hooks that will be called by
65 * uACPI automatically when appropriate if compiled-in.
66 */
67#ifdef UACPI_KERNEL_INITIALIZATION
68/**
69 * This API is invoked for each initialization level so that appropriate parts
70 * of the host kernel and/or glue code can be initialized at different stages.
71 *
72 * uACPI API that triggers calls to uacpi_kernel_initialize and the respective
73 * 'current_init_lvl' passed to the hook at that stage:
74 * 1. uacpi_initialize() -> UACPI_INIT_LEVEL_EARLY
75 * 2. uacpi_namespace_load() -> UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED
76 * 3. (start of) uacpi_namespace_initialize() -> UACPI_INIT_LEVEL_NAMESPACE_LOADED
77 * 4. (end of) uacpi_namespace_initialize() -> UACPI_INIT_LEVEL_NAMESPACE_INITIALIZED
78 */
79uacpi_status uacpi_kernel_initialize(uacpi_init_level current_init_lvl);
80void uacpi_kernel_deinitialize(void);
81#endif
82
83/**
84 * Open a PCI device at 'address' for reading & writing.
85 *
86 * The device at 'address' might not actually exist on the system, in this case
87 * the api is allowed to return UACPI_STATUS_NOT_FOUND to indicate that, this
88 * error is handled gracefully by creating a dummy device internally that always
89 * returns 0xFF on reads and is no-op for writes. This is to support a common
90 * pattern in AML that probes for 0xFF reads to detect whether a device exists.
91 *
92 * The handle returned via 'out_handle' is used to perform IO on the
93 * configuration space of the device.
94 */
95uacpi_status uacpi_kernel_pci_device_open(
96 uacpi_pci_address address, uacpi_handle *out_handle
97);
98void uacpi_kernel_pci_device_close(uacpi_handle);
99
100/**
101 * Read & write the configuration space of a previously open PCI device.
102 */
103uacpi_status uacpi_kernel_pci_read8(
104 uacpi_handle device, uacpi_size offset, uacpi_u8 *value
105);
106uacpi_status uacpi_kernel_pci_read16(
107 uacpi_handle device, uacpi_size offset, uacpi_u16 *value
108);
109uacpi_status uacpi_kernel_pci_read32(
110 uacpi_handle device, uacpi_size offset, uacpi_u32 *value
111);
112
113uacpi_status uacpi_kernel_pci_write8(
114 uacpi_handle device, uacpi_size offset, uacpi_u8 value
115);
116uacpi_status uacpi_kernel_pci_write16(
117 uacpi_handle device, uacpi_size offset, uacpi_u16 value
118);
119uacpi_status uacpi_kernel_pci_write32(
120 uacpi_handle device, uacpi_size offset, uacpi_u32 value
121);
122
123/**
124 * Map a SystemIO address at [base, base + len) and return a kernel-implemented
125 * handle that can be used for reading and writing the IO range.
126 *
127 * NOTE: The x86 architecture uses the in/out family of instructions
128 * to access the SystemIO address space.
129 */
130uacpi_status uacpi_kernel_io_map(
131 uacpi_io_addr base, uacpi_size len, uacpi_handle *out_handle
132);
133void uacpi_kernel_io_unmap(uacpi_handle handle);
134
135/**
136 * Read/Write the IO range mapped via uacpi_kernel_io_map
137 * at a 0-based 'offset' within the range.
138 *
139 * NOTE:
140 * The x86 architecture uses the in/out family of instructions
141 * to access the SystemIO address space.
142 *
143 * You are NOT allowed to break e.g. a 4-byte access into four 1-byte accesses.
144 * Hardware ALWAYS expects accesses to be of the exact width.
145 */
146uacpi_status uacpi_kernel_io_read8(
147 uacpi_handle, uacpi_size offset, uacpi_u8 *out_value
148);
149uacpi_status uacpi_kernel_io_read16(
150 uacpi_handle, uacpi_size offset, uacpi_u16 *out_value
151);
152uacpi_status uacpi_kernel_io_read32(
153 uacpi_handle, uacpi_size offset, uacpi_u32 *out_value
154);
155
156uacpi_status uacpi_kernel_io_write8(
157 uacpi_handle, uacpi_size offset, uacpi_u8 in_value
158);
159uacpi_status uacpi_kernel_io_write16(
160 uacpi_handle, uacpi_size offset, uacpi_u16 in_value
161);
162uacpi_status uacpi_kernel_io_write32(
163 uacpi_handle, uacpi_size offset, uacpi_u32 in_value
164);
165
166/**
167 * Allocate a block of memory of 'size' bytes.
168 * The contents of the allocated memory are unspecified.
169 */
170void *uacpi_kernel_alloc(uacpi_size size);
171
172#ifdef UACPI_NATIVE_ALLOC_ZEROED
173/**
174 * Allocate a block of memory of 'size' bytes.
175 * The returned memory block is expected to be zero-filled.
176 */
177void *uacpi_kernel_alloc_zeroed(uacpi_size size);
178#endif
179
180/**
181 * Free a previously allocated memory block.
182 *
183 * 'mem' might be a NULL pointer. In this case, the call is assumed to be a
184 * no-op.
185 *
186 * An optionally enabled 'size_hint' parameter contains the size of the original
187 * allocation. Note that in some scenarios this incurs additional cost to
188 * calculate the object size.
189 */
190#ifndef UACPI_SIZED_FREES
191void uacpi_kernel_free(void *mem);
192#else
193void uacpi_kernel_free(void *mem, uacpi_size size_hint);
194#endif
195
196/**
197 * Returns the number of nanosecond ticks elapsed since boot,
198 * strictly monotonic.
199 */
200uacpi_u64 uacpi_kernel_get_nanoseconds_since_boot(void);
201
202/**
203 * Spin for N microseconds.
204 */
205void uacpi_kernel_stall(uacpi_u8 usec);
206
207/**
208 * Sleep for N milliseconds.
209 */
210void uacpi_kernel_sleep(uacpi_u64 msec);
211
212/**
213 * Create/free an opaque non-recursive kernel mutex object.
214 */
215uacpi_handle uacpi_kernel_create_mutex(void);
216void uacpi_kernel_free_mutex(uacpi_handle);
217
218/**
219 * Create/free an opaque kernel (semaphore-like) event object.
220 */
221uacpi_handle uacpi_kernel_create_event(void);
222void uacpi_kernel_free_event(uacpi_handle);
223
224/**
225 * Returns a unique identifier of the currently executing thread.
226 *
227 * The returned thread id cannot be UACPI_THREAD_ID_NONE.
228 */
229uacpi_thread_id uacpi_kernel_get_thread_id(void);
230
231/**
232 * Disable interrupts and return an kernel-defined value representing the
233 * "before" state. This value is used in the subsequent call to restore the
234 * prior state.
235 *
236 * Note that this is talking about ALL interrupts on the current CPU, not just
237 * those installed by uACPI. This is typically achieved by executing the 'cli'
238 * instruction on x86, 'msr daifset, #3' on aarch64 etc.
239 */
240uacpi_interrupt_state uacpi_kernel_disable_interrupts(void);
241
242/**
243 * Restore the state of the interrupt flags to the kernel-defined value provided
244 * in 'state'.
245 */
246void uacpi_kernel_restore_interrupts(uacpi_interrupt_state state);
247
248/**
249 * Try to acquire the mutex with a millisecond timeout.
250 *
251 * The timeout value has the following meanings:
252 * 0x0000 - Attempt to acquire the mutex once, in a non-blocking manner
253 * 0x0001...0xFFFE - Attempt to acquire the mutex for at least 'timeout'
254 * milliseconds
255 * 0xFFFF - Infinite wait, block until the mutex is acquired
256 *
257 * The following are possible return values:
258 * 1. UACPI_STATUS_OK - successful acquire operation
259 * 2. UACPI_STATUS_TIMEOUT - timeout reached while attempting to acquire (or the
260 * single attempt to acquire was not successful for
261 * calls with timeout=0)
262 * 3. Any other value - signifies a host internal error and is treated as such
263 */
264uacpi_status uacpi_kernel_acquire_mutex(uacpi_handle, uacpi_u16);
265void uacpi_kernel_release_mutex(uacpi_handle);
266
267/**
268 * Try to wait for an event (counter > 0) with a millisecond timeout.
269 * A timeout value of 0xFFFF implies infinite wait.
270 *
271 * The internal counter is decremented by 1 if wait was successful.
272 *
273 * A successful wait is indicated by returning UACPI_TRUE.
274 */
275uacpi_bool uacpi_kernel_wait_for_event(uacpi_handle, uacpi_u16);
276
277/**
278 * Signal the event object by incrementing its internal counter by 1.
279 *
280 * This function may be used in interrupt contexts.
281 */
282void uacpi_kernel_signal_event(uacpi_handle);
283
284/**
285 * Reset the event counter to 0.
286 */
287void uacpi_kernel_reset_event(uacpi_handle);
288
289/**
290 * Handle a firmware request.
291 *
292 * Currently either a Breakpoint or Fatal operators.
293 */
294uacpi_status uacpi_kernel_handle_firmware_request(uacpi_firmware_request*);
295
296/**
297 * Install an interrupt handler at 'irq', 'ctx' is passed to the provided
298 * handler for every invocation.
299 *
300 * 'out_irq_handle' is set to a kernel-implemented value that can be used to
301 * refer to this handler from other API.
302 */
303uacpi_status uacpi_kernel_install_interrupt_handler(
304 uacpi_u32 irq, uacpi_interrupt_handler, uacpi_handle ctx,
305 uacpi_handle *out_irq_handle
306);
307
308/**
309 * Uninstall an interrupt handler. 'irq_handle' is the value returned via
310 * 'out_irq_handle' during installation.
311 */
312uacpi_status uacpi_kernel_uninstall_interrupt_handler(
313 uacpi_interrupt_handler, uacpi_handle irq_handle
314);
315
316/**
317 * Create/free a kernel spinlock object.
318 *
319 * Unlike other types of locks, spinlocks may be used in interrupt contexts.
320 */
321uacpi_handle uacpi_kernel_create_spinlock(void);
322void uacpi_kernel_free_spinlock(uacpi_handle);
323
324/**
325 * Lock/unlock helpers for spinlocks.
326 *
327 * These are expected to disable interrupts, returning the previous state of cpu
328 * flags, that can be used to possibly re-enable interrupts if they were enabled
329 * before.
330 *
331 * Note that lock is infalliable.
332 */
333uacpi_cpu_flags uacpi_kernel_lock_spinlock(uacpi_handle);
334void uacpi_kernel_unlock_spinlock(uacpi_handle, uacpi_cpu_flags);
335
336typedef enum uacpi_work_type {
337 /**
338 * Schedule a GPE handler method for execution.
339 * This should be scheduled to run on CPU0 to avoid potential SMI-related
340 * firmware bugs.
341 */
342 UACPI_WORK_GPE_EXECUTION,
343
344 /**
345 * Schedule a Notify(device) firmware request for execution.
346 * This can run on any CPU.
347 */
348 UACPI_WORK_NOTIFICATION,
349} uacpi_work_type;
350
351typedef void (*uacpi_work_handler)(uacpi_handle);
352
353/**
354 * Schedules deferred work for execution.
355 * Might be invoked from an interrupt context.
356 */
357uacpi_status uacpi_kernel_schedule_work(
358 uacpi_work_type, uacpi_work_handler, uacpi_handle ctx
359);
360
361/**
362 * Waits for two types of work to finish:
363 * 1. All in-flight interrupts installed via uacpi_kernel_install_interrupt_handler
364 * 2. All work scheduled via uacpi_kernel_schedule_work
365 *
366 * Note that the waits must be done in this order specifically.
367 */
368uacpi_status uacpi_kernel_wait_for_work_completion(void);
369
370#endif // !UACPI_BAREBONES_MODE
371
372#ifdef __cplusplus
373}
374#endif
375