Kernel/acpica - Fiddling
[tpg/acess2.git] / KernelLand / Kernel / arch / x86 / acpica.c
1 /*
2  * Acess2 Kernel (x86 Core)
3  * - By John Hodge (thePowersGang)
4  *
5  * acpica.c
6  * - ACPICA Interface
7  */
8 #define ACPI_DEBUG_OUTPUT       0
9 #define DEBUG   1
10 #define _AcpiModuleName "Shim"
11 #define _COMPONENT      "Acess"
12 #include <acpi.h>
13 #include <timers.h>
14 #include <mutex.h>
15 #include <semaphore.h>
16
17 #define ONEMEG  (1024*1024)
18
19 // === GLOBALS ===
20 // - RSDP Address from uEFI
21 tPAddr  gACPI_RSDPOverride = 0;
22
23 // === PROTOTYPES ===
24 int     ACPICA_Initialise(void);
25 void    ACPI_int_InterruptProxy(int IRQ, void *data);
26
27
28 // === CODE ===
29 int ACPICA_Initialise(void)
30 {
31         ACPI_STATUS     rv;
32
33         #ifdef ACPI_DEBUG_OUTPUT
34         AcpiDbgLevel = ACPI_DB_ALL;
35         #endif
36
37         rv = AcpiInitializeSubsystem();
38         if( ACPI_FAILURE(rv) )
39         {
40                 Log_Error("ACPI", "AcpiInitializeSubsystem: %i", rv);
41                 return -1;
42         }
43         
44         rv = AcpiInitializeTables(NULL, 16, FALSE);
45         if( ACPI_FAILURE(rv) )
46         {
47                 Log_Error("ACPI", "AcpiInitializeTables: %i", rv);
48                 AcpiTerminate();
49                 return -1;
50         }
51
52         rv = AcpiLoadTables();
53         if( ACPI_FAILURE(rv) )
54         {
55                 Log_Error("ACPI", "AcpiLoadTables: %i", rv);
56                 AcpiTerminate();
57                 return -1;
58         }
59         
60         rv = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
61         if( ACPI_FAILURE(rv) )
62         {
63                 Log_Error("ACPI", "AcpiEnableSubsystem: %i", rv);
64                 AcpiTerminate();
65                 return -1;
66         }
67
68         return 0;
69 }
70
71 // ---------------
72 // --- Exports ---
73 // ---------------
74 ACPI_STATUS AcpiOsInitialize(void)
75 {
76         return AE_OK;
77 }
78
79 ACPI_STATUS AcpiOsTerminate(void)
80 {
81         return AE_OK;
82 }
83
84 ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer(void)
85 {
86         ACPI_SIZE       val;
87         ACPI_STATUS     rv;
88
89         if( gACPI_RSDPOverride )
90                 return gACPI_RSDPOverride;      
91
92         rv = AcpiFindRootPointer(&val);
93         if( ACPI_FAILURE(rv) )
94                 return 0;
95
96         LOG("val=0x%x", val);
97         
98         return val;
99         // (Or use EFI)
100 }
101
102 ACPI_STATUS AcpiOsPredefinedOverride(const ACPI_PREDEFINED_NAMES *PredefinedObject, ACPI_STRING *NewValue)
103 {
104         *NewValue = NULL;
105         return AE_OK;
106 }
107
108 ACPI_STATUS AcpiOsTableOverride(ACPI_TABLE_HEADER *ExisitingTable, ACPI_TABLE_HEADER **NewTable)
109 {
110         *NewTable = NULL;
111         return AE_OK;
112 }
113
114 ACPI_STATUS AcpiOsPhysicalTableOverride(ACPI_TABLE_HEADER *ExisitingTable, ACPI_PHYSICAL_ADDRESS *NewAddress, UINT32 *NewTableLength)
115 {
116         *NewAddress = 0;
117         return AE_OK;
118 }
119
120 // -- Memory Management ---
121 struct sACPICache
122 {
123         Uint16  nObj;
124         Uint16  ObjectSize;
125         char    *Name;
126         void    *First;
127         char    ObjectStates[];
128 };
129
130 ACPI_STATUS AcpiOsCreateCache(char *CacheName, UINT16 ObjectSize, UINT16 MaxDepth, ACPI_CACHE_T **ReturnCache)
131 {
132         tACPICache      *ret;
133          int    namelen = (CacheName ? strlen(CacheName) : 0) + 1;
134         LOG("CacheName=%s, ObjSize=%x, MaxDepth=%x", CacheName, ObjectSize, MaxDepth);
135
136         if( ReturnCache == NULL || ObjectSize < 16) {
137                 return AE_BAD_PARAMETER;
138         }
139
140         namelen = (namelen + 3) & ~3;
141
142         ret = malloc(sizeof(*ret) + MaxDepth*sizeof(char) + namelen + MaxDepth*ObjectSize);
143         if( !ret ) {
144                 Log_Notice("ACPICA", "%s: malloc() fail", __func__);
145                 return AE_NO_MEMORY;
146         }
147
148         ret->nObj = MaxDepth;
149         ret->ObjectSize = ObjectSize;
150         ret->Name = (char*)(ret->ObjectStates + MaxDepth);
151         ret->First = ret->Name + namelen;
152         if( CacheName )
153                 strcpy(ret->Name, CacheName);
154         else
155                 ret->Name[0] = 0;
156         memset(ret->ObjectStates, 0, sizeof(char)*MaxDepth);
157         
158         LOG("Allocated cache %p '%s' (%i x 0x%x)", ret, CacheName, MaxDepth, ObjectSize);
159         
160         *ReturnCache = ret;
161         
162         return AE_OK;
163 }
164
165 ACPI_STATUS AcpiOsDeleteCache(ACPI_CACHE_T *Cache)
166 {
167         if( Cache == NULL )
168                 return AE_BAD_PARAMETER;
169
170         free(Cache);
171         return AE_OK;
172 }
173
174 ACPI_STATUS AcpiOsPurgeCache(ACPI_CACHE_T *Cache)
175 {
176         ENTER("pCache", Cache);
177         if( Cache == NULL ) {
178                 LEAVE('i', AE_BAD_PARAMETER);
179                 return AE_BAD_PARAMETER;
180         }
181
182         memset(Cache->ObjectStates, 0, sizeof(char)*Cache->nObj);
183
184         LEAVE('i', AE_OK);
185         return AE_OK;
186 }
187
188 void *AcpiOsAcquireObject(ACPI_CACHE_T *Cache)
189 {
190         ENTER("pCache", Cache);
191         LOG("Called by %p", __builtin_return_address(0));
192         for(int i = 0; i < Cache->nObj; i ++ )
193         {
194                 if( !Cache->ObjectStates[i] ) {
195                         Cache->ObjectStates[i] = 1;
196                         void *rv = (char*)Cache->First + i*Cache->ObjectSize;
197                         if(!rv) {
198                                 LEAVE('n');
199                                 return NULL;
200                         }
201                         memset(rv, 0, Cache->ObjectSize);
202                         LEAVE('p', rv);
203                         return rv;
204                 }
205         }
206
207         Log_Debug("ACPICA", "AcpiOsAcquireObject: All %i objects used in '%s'",
208                 Cache->nObj, Cache->Name);
209
210         LEAVE('n');
211         return NULL;
212 }
213
214 ACPI_STATUS AcpiOsReleaseObject(ACPI_CACHE_T *Cache, void *Object)
215 {
216         if( Cache == NULL || Object == NULL )
217                 return AE_BAD_PARAMETER;
218         ENTER("pCache pObject", Cache, Object);
219
220         tVAddr delta = (tVAddr)Object - (tVAddr)Cache->First;
221         delta /= Cache->ObjectSize;
222         LOG("Cache=%p, delta = %i, (limit %i)", Cache, delta, Cache->nObj);
223         
224         if( delta >= Cache->nObj ) {
225                 LEAVE('i', AE_BAD_PARAMETER);
226                 return AE_BAD_PARAMETER;
227         }
228         
229         Cache->ObjectStates[delta] = 0;
230
231         LEAVE('i', AE_OK);
232         return AE_OK;
233 }
234
235 void *AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, ACPI_SIZE Length)
236 {
237         if( PhysicalAddress < ONEMEG )
238                 return (void*)(KERNEL_BASE | PhysicalAddress);
239         
240         Uint    ofs = PhysicalAddress & (PAGE_SIZE-1);
241         int npages = (ofs + Length + (PAGE_SIZE-1)) / PAGE_SIZE;
242         char *maploc = (void*)MM_MapHWPages(PhysicalAddress, npages);
243         if(!maploc) {
244                 LOG("Mapping %P+0x%x failed", PhysicalAddress, Length);
245                 return NULL;
246         }
247 //      MM_DumpTables(0, -1);
248         void *rv = maploc + ofs;
249         LOG("Map (%P+%i pg) to %p", PhysicalAddress, npages, rv);
250         return rv;
251 }
252
253 void AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Length)
254 {
255         if( (tVAddr)LogicalAddress - KERNEL_BASE < ONEMEG )
256                 return ;
257
258         LOG("%p", LogicalAddress);
259
260         Uint    ofs = (tVAddr)LogicalAddress & (PAGE_SIZE-1);
261         int npages = (ofs + Length + (PAGE_SIZE-1)) / PAGE_SIZE;
262         // TODO: Validate `Length` is the same as was passed to AcpiOsMapMemory
263         MM_UnmapHWPages( (tVAddr)LogicalAddress, npages);
264 }
265
266 ACPI_STATUS AcpiOsGetPhysicalAddress(void *LogicalAddress, ACPI_PHYSICAL_ADDRESS *PhysicalAddress)
267 {
268         if( LogicalAddress == NULL || PhysicalAddress == NULL )
269                 return AE_BAD_PARAMETER;
270         
271         tPAddr  rv = MM_GetPhysAddr(LogicalAddress);
272         if( rv == 0 )
273                 return AE_ERROR;
274         *PhysicalAddress = rv;
275         return AE_OK;
276 }
277
278 void *AcpiOsAllocate(ACPI_SIZE Size)
279 {
280         return malloc(Size);
281 }
282
283 void AcpiOsFree(void *Memory)
284 {
285         return free(Memory);
286 }
287
288 BOOLEAN AcpiOsReadable(void *Memory, ACPI_SIZE Length)
289 {
290         return CheckMem(Memory, Length);
291 }
292
293 BOOLEAN AcpiOsWritable(void *Memory, ACPI_SIZE Length)
294 {
295         // TODO: Actually check if it's writable
296         return CheckMem(Memory, Length);
297 }
298
299
300 // --- Threads ---
301 ACPI_THREAD_ID AcpiOsGetThreadId(void)
302 {
303         return Threads_GetTID() + 1;
304 }
305
306 ACPI_STATUS AcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK Function, void *Context)
307 {
308         // TODO: Need to store currently executing functions
309         if( Function == NULL )
310                 return AE_BAD_PARAMETER;
311         Proc_SpawnWorker(Function, Context);
312         return AE_OK;
313 }
314
315 void AcpiOsSleep(UINT64 Milliseconds)
316 {
317         Time_Delay(Milliseconds);
318 }
319
320 void AcpiOsStall(UINT32 Microseconds)
321 {
322         // TODO: need a microsleep function
323         Microseconds += (1000-1);
324         Microseconds /= 1000;
325         Time_Delay(Microseconds);
326 }
327
328 void AcpiOsWaitEventsComplete(void)
329 {
330         // TODO: 
331 }
332
333 // --- Mutexes etc ---
334 ACPI_STATUS AcpiOsCreateMutex(ACPI_MUTEX *OutHandle)
335 {
336         LOG("()");
337         if( !OutHandle )
338                 return AE_BAD_PARAMETER;
339         tMutex  *ret = calloc( sizeof(tMutex), 1 );
340         if( !ret ) {
341                 Log_Notice("ACPICA", "%s: malloc() fail", __func__);
342                 return AE_NO_MEMORY;
343         }
344         ret->Name = "AcpiOsCreateMutex";
345         *OutHandle = ret;
346         
347         return AE_OK;
348 }
349
350 void AcpiOsDeleteMutex(ACPI_MUTEX Handle)
351 {
352         //  TODO: Need `Mutex_Destroy`
353         Mutex_Acquire(Handle);
354         free(Handle);
355 }
356
357 ACPI_STATUS AcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout)
358 {
359         if( Handle == NULL )
360                 return AE_BAD_PARAMETER;
361
362         Mutex_Acquire(Handle);  
363
364         return AE_OK;
365 }
366
367 void AcpiOsReleaseMutex(ACPI_MUTEX Handle)
368 {
369         Mutex_Release(Handle);
370 }
371
372 ACPI_STATUS AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, ACPI_SEMAPHORE *OutHandle)
373 {
374         LOG("(MaxUnits=%i,InitialUnits=%i)", MaxUnits, InitialUnits);
375         if( !OutHandle )
376                 return AE_BAD_PARAMETER;
377         tSemaphore      *ret = calloc( sizeof(tSemaphore), 1 );
378         if( !ret ) {
379                 Log_Notice("ACPICA", "%s: malloc() fail", __func__);
380                 return AE_NO_MEMORY;
381         }
382         
383         Semaphore_Init(ret, InitialUnits, MaxUnits, "AcpiOsCreateSemaphore", "");
384         *OutHandle = ret;
385         return AE_OK;
386 }
387
388 ACPI_STATUS AcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle)
389 {
390         if( !Handle )
391                 return AE_BAD_PARAMETER;
392
393         free(Handle);   
394
395         return AE_OK;
396 }
397
398 ACPI_STATUS AcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout)
399 {
400         if( !Handle )
401                 return AE_BAD_PARAMETER;
402
403         // Special case
404         if( Timeout == 0 )
405         {
406                 // NOTE: Possible race condition
407                 if( Semaphore_GetValue(Handle) >= Units ) {
408                         Semaphore_Wait(Handle, Units);
409                         return AE_OK;
410                 }
411                 return AE_TIME;
412         }
413
414         tTime   start = now();
415         UINT32  rem = Units;
416         while(rem && now() - start < Timeout)
417         {
418                 rem -= Semaphore_Wait(Handle, rem);
419         }
420
421         if( rem ) {
422                 Semaphore_Signal(Handle, Units - rem);
423                 return AE_TIME;
424         }
425
426         return AE_OK;
427 }
428
429 ACPI_STATUS AcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
430 {
431         if( !Handle )
432                 return AE_BAD_PARAMETER;
433
434         // TODO: Support AE_LIMIT detection early (to avoid blocks)
435
436         // NOTE: Blocks
437         int rv = Semaphore_Signal(Handle, Units);
438         if( rv != Units )
439                 return AE_LIMIT;
440         
441         return AE_OK;
442 }
443
444 ACPI_STATUS AcpiOsCreateLock(ACPI_SPINLOCK *OutHandle)
445 {
446         LOG("()");
447         if( !OutHandle )
448                 return AE_BAD_PARAMETER;
449         tShortSpinlock  *lock = calloc(sizeof(tShortSpinlock), 1);
450         if( !lock )
451                 return AE_NO_MEMORY;
452         
453         *OutHandle = lock;
454         return AE_OK;
455 }
456
457 void AcpiOsDeleteLock(ACPI_SPINLOCK Handle)
458 {
459         free(Handle);
460 }
461
462 ACPI_CPU_FLAGS AcpiOsAcquireLock(ACPI_SPINLOCK Handle)
463 {
464         SHORTLOCK(Handle);
465         return 0;
466 }
467
468 void AcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
469 {
470         SHORTREL(Handle);
471 }
472
473 // --- Interrupt handling ---
474 #define N_INT_LEVELS    16
475 ACPI_OSD_HANDLER        gaACPI_InterruptHandlers[N_INT_LEVELS];
476 void    *gaACPI_InterruptData[N_INT_LEVELS];
477  int    gaACPI_InterruptHandles[N_INT_LEVELS];
478
479 void ACPI_int_InterruptProxy(int IRQ, void *data)
480 {
481         if( !gaACPI_InterruptHandlers[IRQ] )
482                 return ;
483         gaACPI_InterruptHandlers[IRQ](gaACPI_InterruptData[IRQ]);
484 }
485
486 ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 InterruptLevel, ACPI_OSD_HANDLER Handler, void *Context)
487 {
488         if( InterruptLevel >= N_INT_LEVELS || Handler == NULL )
489                 return AE_BAD_PARAMETER;
490         if( gaACPI_InterruptHandlers[InterruptLevel] )
491                 return AE_ALREADY_EXISTS;
492
493         gaACPI_InterruptHandlers[InterruptLevel] = Handler;
494         gaACPI_InterruptData[InterruptLevel] = Context;
495
496         gaACPI_InterruptHandles[InterruptLevel] = IRQ_AddHandler(InterruptLevel, ACPI_int_InterruptProxy, NULL);
497         return AE_OK;
498 }
499
500 ACPI_STATUS AcpiOsRemoveInterruptHandler(UINT32 InterruptLevel, ACPI_OSD_HANDLER Handler)
501 {
502         if( InterruptLevel >= N_INT_LEVELS || Handler == NULL )
503                 return AE_BAD_PARAMETER;
504         if( gaACPI_InterruptHandlers[InterruptLevel] != Handler )
505                 return AE_NOT_EXIST;
506         gaACPI_InterruptHandlers[InterruptLevel] = NULL;
507         IRQ_RemHandler(gaACPI_InterruptHandles[InterruptLevel]);
508         return AE_OK;
509 }
510
511 // --- Memory Access ---
512 ACPI_STATUS AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 *Value, UINT32 Width)
513 {
514         void *ptr;
515         if( Address < ONEMEG ) {
516                 ptr = (void*)(KERNEL_BASE | Address);
517         }
518         else {
519                 ptr = (char*)MM_MapTemp(Address) + (Address & 0xFFF);
520         }
521
522         switch(Width)
523         {
524         case 8:         *Value = *(Uint8 *)ptr; break;
525         case 16:        *Value = *(Uint16*)ptr; break;
526         case 32:        *Value = *(Uint32*)ptr; break;
527         case 64:        *Value = *(Uint64*)ptr; break;
528         }
529
530         if( Address >= ONEMEG ) {
531                 MM_FreeTemp(ptr);
532         }
533
534         return AE_OK;
535 }
536
537 ACPI_STATUS AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 Value, UINT32 Width)
538 {
539         void *ptr;
540         if( Address < ONEMEG ) {
541                 ptr = (void*)(KERNEL_BASE | Address);
542         }
543         else {
544                 ptr = (char*)MM_MapTemp(Address) + (Address & 0xFFF);
545         }
546
547         switch(Width)
548         {
549         case 8:         *(Uint8 *)ptr = Value;  break;
550         case 16:        *(Uint16*)ptr = Value;  break;
551         case 32:        *(Uint32*)ptr = Value;  break;
552         case 64:        *(Uint64*)ptr = Value;  break;
553         default:
554                 return AE_BAD_PARAMETER;
555         }
556
557         if( Address >= 1024*1024 ) {
558                 MM_FreeTemp(ptr);
559         }
560         
561         return AE_OK;
562 }
563
564 // --- Port Input / Output ---
565 ACPI_STATUS AcpiOsReadPort(ACPI_IO_ADDRESS Address, UINT32 *Value, UINT32 Width)
566 {
567         switch(Width)
568         {
569         case 8:         *Value = inb(Address);  break;
570         case 16:        *Value = inw(Address);  break;
571         case 32:        *Value = ind(Address);  break;
572         default:
573                 return AE_BAD_PARAMETER;
574         }
575         return AE_OK;
576 }
577
578 ACPI_STATUS AcpiOsWritePort(ACPI_IO_ADDRESS Address, UINT32 Value, UINT32 Width)
579 {
580         switch(Width)
581         {
582         case 8:         outb(Address, Value);   break;
583         case 16:        outw(Address, Value);   break;
584         case 32:        outd(Address, Value);   break;
585         default:
586                 return AE_BAD_PARAMETER;
587         }
588         return AE_OK;
589 }
590
591 // --- PCI Configuration Space Access ---
592 ACPI_STATUS AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, UINT64 *Value, UINT32 Width)
593 {
594         UNIMPLEMENTED();
595         return AE_NOT_IMPLEMENTED;
596 }
597
598 ACPI_STATUS AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, UINT64 Value, UINT32 Width)
599 {
600         UNIMPLEMENTED();
601         return AE_NOT_IMPLEMENTED;
602 }
603
604 // --- Formatted Output ---
605 void AcpiOsPrintf(const char *Format, ...)
606 {
607         va_list args;
608         va_start(args, Format);
609
610         LogFV(Format, args);
611
612         va_end(args);
613 }
614
615 void AcpiOsVprintf(const char *Format, va_list Args)
616 {
617         LogFV(Format, Args);
618 }
619
620 void AcpiOsRedirectOutput(void *Destination)
621 {
622         // TODO: Do I even need to impliment this?
623 }
624
625 // --- Miscellaneous ---
626 UINT64 AcpiOsGetTimer(void)
627 {
628         return now() * 10 * 1000;
629 }
630
631 ACPI_STATUS AcpiOsSignal(UINT32 Function, void *Info)
632 {
633         switch(Function)
634         {
635         case ACPI_SIGNAL_FATAL: {
636                 ACPI_SIGNAL_FATAL_INFO  *finfo = Info;
637                 Log_Error("ACPI AML", "Fatal %x %x %x", finfo->Type, finfo->Code, finfo->Argument);
638                 break; }
639         case ACPI_SIGNAL_BREAKPOINT: {
640                 Log_Notice("ACPI AML", "Breakpoint %s", Info);
641                 break; };
642         }
643         return AE_OK;
644 }
645
646 ACPI_STATUS AcpiOsGetLine(char *Buffer, UINT32 BufferLength, UINT32 *BytesRead)
647 {
648         UNIMPLEMENTED();
649         return AE_NOT_IMPLEMENTED;
650 }
651

UCC git Repository :: git.ucc.asn.au