Implement serial logging. Finish modularizing power management.
[monolithium.git] / drivers / acpica / src / osmlxf.c
1 /*
2  * osmlxf.c (Monolithium ACPICA OSL)
3  *
4  * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as
8  * published by the Free Software Foundation, either version 3 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <common.h>
21 #include <log.h>
22 #include <heap.h>
23 #include <memory.h>
24 #include <thread.h>
25 #include <cpu.h>
26 #include <timer.h>
27 #include <interrupt.h>
28 #include <acpi.h>
29 #include <stdio.h>
30 #include <power.h>
31
32 const char driver_name[] = "acpica";
33
34 static ACPI_OSD_HANDLER acpica_int_handlers[256] = { NULL };
35 static void *acpica_int_contexts[256] = { NULL };
36
37 static void acpica_osl_handler(registers_t *regs, byte_t int_num)
38 {
39     acpica_int_handlers[int_num](acpica_int_contexts[int_num]);
40 }
41
42 ACPI_STATUS AcpiOsInitialize(void)
43 {
44     return AE_OK;
45 }
46
47 ACPI_STATUS AcpiOsTerminate(void)
48 {
49     return AE_OK;
50 }
51
52 ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer(void)
53 {
54     ACPI_PHYSICAL_ADDRESS Address;
55     AcpiFindRootPointer(&Address);
56     return Address;
57 }
58
59 ACPI_STATUS AcpiOsPredefinedOverride(const ACPI_PREDEFINED_NAMES *PredefinedObject, ACPI_STRING *NewValue)
60 {
61     *NewValue = NULL;
62     return AE_OK;
63 }
64
65 ACPI_STATUS AcpiOsTableOverride(ACPI_TABLE_HEADER *ExistingTable, ACPI_TABLE_HEADER **NewTable)
66 {
67     *NewTable = NULL;
68     return AE_OK;
69 }
70
71 ACPI_STATUS AcpiOsPhysicalTableOverride(ACPI_TABLE_HEADER *ExistingTable, ACPI_PHYSICAL_ADDRESS *NewAddress, UINT32 *NewTableLength)
72 {
73     *NewAddress = 0;
74     return AE_OK;
75 }
76
77 ACPI_STATUS AcpiOsSignal(UINT32 Function, void *Info)
78 {
79     return AE_SUPPORT; // TODO
80 }
81
82 void AcpiOsVprintf(const char *Format, va_list Args)
83 {
84     char buffer[MAX_LOG_MESSAGE_SIZE];
85     vsnprintf(buffer, MAX_LOG_MESSAGE_SIZE, Format, Args);
86     log_write(LOG_NORMAL, buffer);
87 }
88
89 void AcpiOsPrintf(const char *Format, ...)
90 {
91     va_list args;
92     va_start(args, Format);
93     AcpiOsVprintf(Format, args);
94     va_end(args);
95 }
96
97 ACPI_STATUS AcpiOsReadPort(ACPI_IO_ADDRESS Address, UINT32 *Value, UINT32 Width)
98 {
99     switch (Width)
100     {
101     case 8:
102         *Value = inportb(Address);
103         break;
104     case 16:
105         *Value = inportw(Address);
106         break;
107     case 32:
108         *Value = inportl(Address);
109         break;
110     default:
111         return AE_SUPPORT;
112     }
113
114     return AE_OK;
115 }
116
117 ACPI_STATUS AcpiOsWritePort(ACPI_IO_ADDRESS Address, UINT32 Value, UINT32 Width)
118 {
119     switch (Width)
120     {
121     case 8:
122         outportb(Address, Value);
123         break;
124     case 16:
125         outportw(Address, Value);
126         break;
127     case 32:
128         outportl(Address, Value);
129         break;
130     default:
131         return AE_SUPPORT;
132     }
133
134     return AE_OK;
135 }
136
137 void *AcpiOsAllocate(ACPI_SIZE Size)
138 {
139     return malloc(Size);
140 }
141
142 void AcpiOsFree(void *Memory)
143 {
144     free(Memory);
145 }
146
147 ACPI_STATUS AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 *Value, UINT32 Width)
148 {
149     *Value = 0;
150     dword_t ret = read_physical((void*)((uintptr_t)Address), Value, Width / 8);
151
152     if (ret == ERR_SUCCESS) return AE_OK;
153     if (ret == ERR_NOMEMORY) return AE_NO_MEMORY;
154     return AE_ERROR;
155 }
156
157 ACPI_STATUS AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 Value, UINT32 Width)
158 {
159     dword_t ret = write_physical((void*)((uintptr_t)Address), &Value, Width / 8);
160
161     if (ret == ERR_SUCCESS) return AE_OK;
162     if (ret == ERR_NOMEMORY) return AE_NO_MEMORY;
163     return AE_ERROR;
164 }
165
166 void *AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Address, ACPI_SIZE Length)
167 {
168     void *virtual = NULL;
169
170     if (map_memory((void*)PAGE_ALIGN((uintptr_t)Address),
171                    &virtual,
172                    PAGE_ALIGN_UP(PAGE_OFFSET((uintptr_t)Address) + Length),
173                    MEMORY_BLOCK_ACCESSIBLE | MEMORY_BLOCK_WRITABLE) == ERR_SUCCESS)
174     {
175         return (void*)((uintptr_t)virtual + PAGE_OFFSET((uintptr_t)Address));
176     }
177     else
178     {
179         return NULL;
180     }
181 }
182
183 void AcpiOsUnmapMemory(void *Address, ACPI_SIZE Length)
184 {
185     UNUSED_PARAMETER(Length);
186     unmap_memory(Address);
187 }
188
189 ACPI_STATUS AcpiOsCreateLock(ACPI_SPINLOCK *OutHandle)
190 {
191     *OutHandle = malloc(sizeof(critical_t));
192     if (*OutHandle == NULL) return AE_NO_MEMORY;
193     return AE_OK;
194 }
195
196 void AcpiOsDeleteLock(ACPI_SPINLOCK Handle)
197 {
198     free(Handle);
199 }
200
201 ACPI_CPU_FLAGS AcpiOsAcquireLock(ACPI_SPINLOCK Handle)
202 {
203     enter_critical(Handle);
204     return *(critical_t*)Handle;
205 }
206
207 void AcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
208 {
209     UNUSED_PARAMETER(Flags);
210     leave_critical(Handle);
211 }
212
213 ACPI_STATUS AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, ACPI_SEMAPHORE *OutHandle)
214 {
215     semaphore_t *semaphore = malloc(sizeof(semaphore_t));
216     if (semaphore == NULL) return AE_NO_MEMORY;
217
218     init_semaphore(semaphore, InitialUnits, MaxUnits);
219     *OutHandle = (ACPI_SEMAPHORE)semaphore;
220     return AE_OK;
221 }
222
223 ACPI_STATUS AcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle)
224 {
225     free(Handle);
226     return AE_OK;
227 }
228
229 ACPI_STATUS AcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout)
230 {
231     dword_t ret = wait_semaphore((semaphore_t*)Handle, Units, (int32_t)((int16_t)Timeout));
232
233     if (ret == ERR_SUCCESS) return AE_OK;
234     else if (ret == ERR_TIMEOUT) return AE_TIME;
235     else return AE_ERROR;
236 }
237
238 ACPI_STATUS AcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
239 {
240     release_semaphore((semaphore_t*)Handle, Units);
241     return AE_OK;
242 }
243
244 UINT64 AcpiOsGetTimer(void)
245 {
246     return syscall_get_nanoseconds() / 100ULL;
247 }
248
249 void AcpiOsSleep(UINT64 Milliseconds)
250 {
251     syscall_sleep(Milliseconds);
252 }
253
254 void AcpiOsStall(UINT32 Microseconds)
255 {
256     qword_t end_time = syscall_get_nanoseconds() + (qword_t)Microseconds * 1000ULL;
257     while (syscall_get_nanoseconds() < end_time) continue;
258 }
259
260 ACPI_THREAD_ID AcpiOsGetThreadId(void)
261 {
262     return get_current_thread()->tid + 1;
263 }
264
265 ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 InterruptLevel, ACPI_OSD_HANDLER Handler, void *Context)
266 {
267     if (InterruptLevel >= 256) return AE_BAD_PARAMETER;
268
269     acpica_int_handlers[InterruptLevel] = Handler;
270     acpica_int_contexts[InterruptLevel] = Context;
271     return AE_OK;
272 }
273
274 ACPI_STATUS AcpiOsRemoveInterruptHandler(UINT32 InterruptLevel, ACPI_OSD_HANDLER Handler)
275 {
276     acpica_int_handlers[InterruptLevel] = NULL;
277     acpica_int_contexts[InterruptLevel] = NULL;
278     return AE_OK;
279 }
280
281 ACPI_STATUS AcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK Function, void *Context)
282 {
283     thread_t *thread;
284     dword_t ret = create_system_thread((thread_procedure_t)Function, 0, THREAD_PRIORITY_MID, 0, Context, &thread);
285
286     if (ret == ERR_SUCCESS)
287     {
288         dereference(&thread->header);
289         return AE_OK;
290     }
291     else if (ret == ERR_INVALID)
292     {
293         return AE_BAD_PARAMETER;
294     }
295     else
296     {
297         return AE_ERROR;
298     }
299 }
300
301 void AcpiOsWaitEventsComplete(void)
302 {
303     // TODO
304 }
305
306 ACPI_STATUS AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, UINT64 *Value, UINT32 Width)
307 {
308     return AE_SUPPORT; // TODO
309 }
310
311 ACPI_STATUS AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, UINT64 Value, UINT32 Width)
312 {
313      return AE_SUPPORT; // TODO
314 }
315
316 dword_t acpica_set_state(power_state_t state)
317 {
318     switch (state)
319     {
320     case POWER_STATE_STANDBY:
321     case POWER_STATE_SUSPEND:
322         /* Not implemented */
323         return ERR_NOSYSCALL;
324
325     case POWER_STATE_OFF:
326         AcpiEnterSleepStatePrep(ACPI_STATE_S5);
327         disable_ints();
328         AcpiEnterSleepState(ACPI_STATE_S5);
329         break;
330
331     default:
332         return ERR_INVALID;
333     }
334
335     return ERR_SUCCESS;
336 }
337
338 dword_t driver_load(const char *parameters)
339 {
340     static power_callbacks_t callbacks = {
341         .set_state = acpica_set_state,
342     };
343
344     dword_t ret = register_power_callbacks(&callbacks);
345     if (ret != ERR_SUCCESS) return ret;
346
347     if (ACPI_FAILURE(AcpiInitializeSubsystem())
348         || ACPI_FAILURE(AcpiInitializeTables(NULL, 16, FALSE))
349         || ACPI_FAILURE(AcpiLoadTables())
350         || ACPI_FAILURE(AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION)))
351     {
352         register_power_callbacks(NULL);
353         return ERR_HARDWARE;
354     }
355
356     return ERR_SUCCESS;
357 }