| 1 | #pragma once |
| 2 | |
| 3 | #include <uacpi/types.h> |
| 4 | #include <uacpi/platform/arch_helpers.h> |
| 5 | |
| 6 | #ifdef __cplusplus |
| 7 | extern "C" { |
| 8 | #endif |
| 9 | |
| 10 | // Returns the PHYSICAL address of the RSDP structure via *out_rsdp_address. |
| 11 | uacpi_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 | */ |
| 37 | void *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 | */ |
| 47 | void uacpi_kernel_unmap(void *addr, uacpi_size len); |
| 48 | |
| 49 | #ifndef UACPI_FORMATTED_LOGGING |
| 50 | void uacpi_kernel_log(uacpi_log_level, const uacpi_char*); |
| 51 | #else |
| 52 | UACPI_PRINTF_DECL(2, 3) |
| 53 | void uacpi_kernel_log(uacpi_log_level, const uacpi_char*, ...); |
| 54 | void 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 | */ |
| 79 | uacpi_status uacpi_kernel_initialize(uacpi_init_level current_init_lvl); |
| 80 | void 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 | */ |
| 95 | uacpi_status uacpi_kernel_pci_device_open( |
| 96 | uacpi_pci_address address, uacpi_handle *out_handle |
| 97 | ); |
| 98 | void uacpi_kernel_pci_device_close(uacpi_handle); |
| 99 | |
| 100 | /** |
| 101 | * Read & write the configuration space of a previously open PCI device. |
| 102 | */ |
| 103 | uacpi_status uacpi_kernel_pci_read8( |
| 104 | uacpi_handle device, uacpi_size offset, uacpi_u8 *value |
| 105 | ); |
| 106 | uacpi_status uacpi_kernel_pci_read16( |
| 107 | uacpi_handle device, uacpi_size offset, uacpi_u16 *value |
| 108 | ); |
| 109 | uacpi_status uacpi_kernel_pci_read32( |
| 110 | uacpi_handle device, uacpi_size offset, uacpi_u32 *value |
| 111 | ); |
| 112 | |
| 113 | uacpi_status uacpi_kernel_pci_write8( |
| 114 | uacpi_handle device, uacpi_size offset, uacpi_u8 value |
| 115 | ); |
| 116 | uacpi_status uacpi_kernel_pci_write16( |
| 117 | uacpi_handle device, uacpi_size offset, uacpi_u16 value |
| 118 | ); |
| 119 | uacpi_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 | */ |
| 130 | uacpi_status uacpi_kernel_io_map( |
| 131 | uacpi_io_addr base, uacpi_size len, uacpi_handle *out_handle |
| 132 | ); |
| 133 | void 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 | */ |
| 146 | uacpi_status uacpi_kernel_io_read8( |
| 147 | uacpi_handle, uacpi_size offset, uacpi_u8 *out_value |
| 148 | ); |
| 149 | uacpi_status uacpi_kernel_io_read16( |
| 150 | uacpi_handle, uacpi_size offset, uacpi_u16 *out_value |
| 151 | ); |
| 152 | uacpi_status uacpi_kernel_io_read32( |
| 153 | uacpi_handle, uacpi_size offset, uacpi_u32 *out_value |
| 154 | ); |
| 155 | |
| 156 | uacpi_status uacpi_kernel_io_write8( |
| 157 | uacpi_handle, uacpi_size offset, uacpi_u8 in_value |
| 158 | ); |
| 159 | uacpi_status uacpi_kernel_io_write16( |
| 160 | uacpi_handle, uacpi_size offset, uacpi_u16 in_value |
| 161 | ); |
| 162 | uacpi_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 | */ |
| 170 | void *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 | */ |
| 177 | void *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 |
| 191 | void uacpi_kernel_free(void *mem); |
| 192 | #else |
| 193 | void 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 | */ |
| 200 | uacpi_u64 uacpi_kernel_get_nanoseconds_since_boot(void); |
| 201 | |
| 202 | /** |
| 203 | * Spin for N microseconds. |
| 204 | */ |
| 205 | void uacpi_kernel_stall(uacpi_u8 usec); |
| 206 | |
| 207 | /** |
| 208 | * Sleep for N milliseconds. |
| 209 | */ |
| 210 | void uacpi_kernel_sleep(uacpi_u64 msec); |
| 211 | |
| 212 | /** |
| 213 | * Create/free an opaque non-recursive kernel mutex object. |
| 214 | */ |
| 215 | uacpi_handle uacpi_kernel_create_mutex(void); |
| 216 | void uacpi_kernel_free_mutex(uacpi_handle); |
| 217 | |
| 218 | /** |
| 219 | * Create/free an opaque kernel (semaphore-like) event object. |
| 220 | */ |
| 221 | uacpi_handle uacpi_kernel_create_event(void); |
| 222 | void 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 | */ |
| 229 | uacpi_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 | */ |
| 240 | uacpi_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 | */ |
| 246 | void 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 | */ |
| 264 | uacpi_status uacpi_kernel_acquire_mutex(uacpi_handle, uacpi_u16); |
| 265 | void 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 | */ |
| 275 | uacpi_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 | */ |
| 282 | void uacpi_kernel_signal_event(uacpi_handle); |
| 283 | |
| 284 | /** |
| 285 | * Reset the event counter to 0. |
| 286 | */ |
| 287 | void uacpi_kernel_reset_event(uacpi_handle); |
| 288 | |
| 289 | /** |
| 290 | * Handle a firmware request. |
| 291 | * |
| 292 | * Currently either a Breakpoint or Fatal operators. |
| 293 | */ |
| 294 | uacpi_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 | */ |
| 303 | uacpi_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 | */ |
| 312 | uacpi_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 | */ |
| 321 | uacpi_handle uacpi_kernel_create_spinlock(void); |
| 322 | void 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 | */ |
| 333 | uacpi_cpu_flags uacpi_kernel_lock_spinlock(uacpi_handle); |
| 334 | void uacpi_kernel_unlock_spinlock(uacpi_handle, uacpi_cpu_flags); |
| 335 | |
| 336 | typedef 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 | |
| 351 | typedef void (*uacpi_work_handler)(uacpi_handle); |
| 352 | |
| 353 | /** |
| 354 | * Schedules deferred work for execution. |
| 355 | * Might be invoked from an interrupt context. |
| 356 | */ |
| 357 | uacpi_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 | */ |
| 368 | uacpi_status uacpi_kernel_wait_for_work_completion(void); |
| 369 | |
| 370 | #endif // !UACPI_BAREBONES_MODE |
| 371 | |
| 372 | #ifdef __cplusplus |
| 373 | } |
| 374 | #endif |
| 375 | |