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