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