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

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