mirror of https://gitlab.com/nakst/essence
626 lines
19 KiB
C++
626 lines
19 KiB
C++
// This file is part of the Essence operating system.
|
|
// It is released under the terms of the MIT license -- see LICENSE.md.
|
|
// Written by: nakst.
|
|
|
|
// TODO Warning: Not all of the OSL has been tested.
|
|
|
|
extern "C" {
|
|
#pragma GCC diagnostic ignored "-Wunused-parameter" push
|
|
#include <ports/acpica/include/acpi.h>
|
|
#pragma GCC diagnostic pop
|
|
}
|
|
|
|
struct ACPICAEvent {
|
|
ACPI_OSD_EXEC_CALLBACK function;
|
|
void *context;
|
|
};
|
|
|
|
// TODO Can these arrays be made smaller?
|
|
Thread *acpiEvents[256];
|
|
size_t acpiEventCount;
|
|
ACPI_OSD_HANDLER acpiInterruptHandlers[256];
|
|
void *acpiInterruptContexts[256];
|
|
uint8_t acpicaPageBuffer[K_PAGE_SIZE];
|
|
KMutex acpicaPageBufferMutex;
|
|
char acpiPrintf[4096];
|
|
bool acpiOSLayerActive = false;
|
|
KAsyncTask powerButtonAsyncTask;
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsInitialize() {
|
|
if (acpiOSLayerActive) KernelPanic("AcpiOsInitialize - ACPI has already been initialised.\n");
|
|
acpiOSLayerActive = true;
|
|
KernelLog(LOG_INFO, "ACPI", "initialise ACPICA", "AcpiOsInitialize - Initialising ACPICA OS layer...\n");
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsTerminate() {
|
|
if (!acpiOSLayerActive) KernelPanic("AcpiOsTerminate - ACPI has not been initialised.\n");
|
|
acpiOSLayerActive = false;
|
|
KernelLog(LOG_INFO, "ACPI", "terminate ACPICA", "AcpiOsTerminate - Terminating ACPICA OS layer...\n");
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer() {
|
|
return ArchFindRootSystemDescriptorPointer();
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsPredefinedOverride(const ACPI_PREDEFINED_NAMES *predefinedObject, ACPI_STRING *newValue) {
|
|
(void) predefinedObject;
|
|
*newValue = nullptr;
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsTableOverride(ACPI_TABLE_HEADER *existingTable, ACPI_TABLE_HEADER **newTable) {
|
|
(void) existingTable;
|
|
*newTable = nullptr;
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsPhysicalTableOverride(ACPI_TABLE_HEADER *existingTable, ACPI_PHYSICAL_ADDRESS *newAddress, uint32_t *newTableLength) {
|
|
(void) existingTable;
|
|
*newAddress = 0;
|
|
*newTableLength = 0;
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C void *AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS physicalAddress, ACPI_SIZE length) {
|
|
return ACPIMapPhysicalMemory(physicalAddress, length);
|
|
}
|
|
|
|
ES_EXTERN_C void AcpiOsUnmapMemory(void *address, ACPI_SIZE length) {
|
|
(void) length;
|
|
MMFree(kernelMMSpace, address);
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsGetPhysicalAddress(void *virtualAddress, ACPI_PHYSICAL_ADDRESS *physicalAddress) {
|
|
if (!virtualAddress || !physicalAddress) {
|
|
return AE_BAD_PARAMETER;
|
|
}
|
|
|
|
*physicalAddress = MMArchTranslateAddress(kernelMMSpace, (uintptr_t) virtualAddress);
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C void *AcpiOsAllocate(ACPI_SIZE size) {
|
|
return EsHeapAllocate(size, false, K_FIXED);
|
|
}
|
|
|
|
ES_EXTERN_C void AcpiOsFree(void *memory) {
|
|
EsHeapFree(memory, 0, K_FIXED);
|
|
}
|
|
|
|
ES_EXTERN_C BOOLEAN AcpiOsReadable(void *memory, ACPI_SIZE length) {
|
|
(void) memory;
|
|
(void) length;
|
|
// This is only used by the debugger, which we don't use...
|
|
return TRUE;
|
|
}
|
|
|
|
ES_EXTERN_C BOOLEAN AcpiOsWritable(void *memory, ACPI_SIZE length) {
|
|
(void) memory;
|
|
(void) length;
|
|
// This is only used by the debugger, which we don't use...
|
|
return TRUE;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_THREAD_ID AcpiOsGetThreadId() {
|
|
return GetCurrentThread()->id + 1;
|
|
}
|
|
|
|
void RunACPICAEvent(void *e) {
|
|
ACPICAEvent *event = (ACPICAEvent *) e;
|
|
event->function(event->context);
|
|
EsHeapFree(event, 0, K_FIXED);
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsExecute(ACPI_EXECUTE_TYPE type, ACPI_OSD_EXEC_CALLBACK function, void *context) {
|
|
(void) type;
|
|
|
|
if (!function) return AE_BAD_PARAMETER;
|
|
|
|
ACPICAEvent *event = (ACPICAEvent *) EsHeapAllocate(sizeof(ACPICAEvent), true, K_FIXED);
|
|
event->function = function;
|
|
event->context = context;
|
|
|
|
Thread *thread = ThreadSpawn("ACPICAEvent", (uintptr_t) RunACPICAEvent, (uintptr_t) event);
|
|
|
|
if (acpiEventCount == 256) {
|
|
KernelPanic("AcpiOsExecute - Exceeded maximum event count, 256.\n");
|
|
}
|
|
|
|
if (thread) {
|
|
acpiEvents[acpiEventCount++] = thread;
|
|
return AE_OK;
|
|
} else {
|
|
return AE_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
ES_EXTERN_C void AcpiOsSleep(UINT64 ms) {
|
|
KEvent event = {};
|
|
KEventWait(&event, ms);
|
|
}
|
|
|
|
ES_EXTERN_C void AcpiOsStall(UINT32 mcs) {
|
|
(void) mcs;
|
|
uint64_t start = ProcessorReadTimeStamp();
|
|
uint64_t end = start + mcs * (timeStampTicksPerMs / 1000);
|
|
while (ProcessorReadTimeStamp() < end);
|
|
}
|
|
|
|
ES_EXTERN_C void AcpiOsWaitEventsComplete() {
|
|
for (uintptr_t i = 0; i < acpiEventCount; i++) {
|
|
Thread *thread = acpiEvents[i];
|
|
KEventWait(&thread->killedEvent, ES_WAIT_NO_TIMEOUT);
|
|
CloseHandleToObject(thread, KERNEL_OBJECT_THREAD);
|
|
}
|
|
|
|
acpiEventCount = 0;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsCreateSemaphore(UINT32 maxUnits, UINT32 initialUnits, ACPI_SEMAPHORE *handle) {
|
|
if (!handle) return AE_BAD_PARAMETER;
|
|
|
|
KSemaphore *semaphore = (KSemaphore *) EsHeapAllocate(sizeof(KSemaphore), true, K_FIXED);
|
|
KSemaphoreReturn(semaphore, initialUnits);
|
|
semaphore->_custom = maxUnits;
|
|
*handle = semaphore;
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsDeleteSemaphore(ACPI_SEMAPHORE handle) {
|
|
if (!handle) return AE_BAD_PARAMETER;
|
|
EsHeapFree(handle, sizeof(KSemaphore), K_FIXED);
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsWaitSemaphore(ACPI_SEMAPHORE handle, UINT32 units, UINT16 timeout) {
|
|
(void) timeout;
|
|
if (!handle) return AE_BAD_PARAMETER;
|
|
KSemaphore *semaphore = (KSemaphore *) handle;
|
|
|
|
if (KSemaphoreTake(semaphore, units, timeout == (UINT16) -1 ? ES_WAIT_NO_TIMEOUT : timeout)) {
|
|
return AE_OK;
|
|
} else {
|
|
return AE_TIME;
|
|
}
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsSignalSemaphore(ACPI_SEMAPHORE handle, UINT32 units) {
|
|
if (!handle) return AE_BAD_PARAMETER;
|
|
KSemaphore *semaphore = (KSemaphore *) handle;
|
|
if (semaphore->units + units > semaphore->_custom) return AE_LIMIT;
|
|
KSemaphoreReturn(semaphore, units);
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsCreateLock(ACPI_SPINLOCK *handle) {
|
|
if (!handle) return AE_BAD_PARAMETER;
|
|
KSpinlock *spinlock = (KSpinlock *) EsHeapAllocate(sizeof(KSpinlock), true, K_FIXED);
|
|
*handle = spinlock;
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C void AcpiOsDeleteLock(ACPI_HANDLE handle) {
|
|
EsHeapFree(handle, sizeof(KSpinlock), K_FIXED);
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_CPU_FLAGS AcpiOsAcquireLock(ACPI_SPINLOCK handle) {
|
|
KSpinlock *spinlock = (KSpinlock *) handle;
|
|
KSpinlockAcquire(spinlock);
|
|
return 0;
|
|
}
|
|
|
|
ES_EXTERN_C void AcpiOsReleaseLock(ACPI_SPINLOCK handle, ACPI_CPU_FLAGS flags) {
|
|
(void) flags;
|
|
KSpinlock *spinlock = (KSpinlock *) handle;
|
|
KSpinlockRelease(spinlock);
|
|
}
|
|
|
|
bool ACPIInterrupt(uintptr_t interruptIndex, void *) {
|
|
if (acpiInterruptHandlers[interruptIndex]) {
|
|
return ACPI_INTERRUPT_HANDLED == acpiInterruptHandlers[interruptIndex](acpiInterruptContexts[interruptIndex]);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 interruptLevel, ACPI_OSD_HANDLER handler, void *context) {
|
|
if (interruptLevel > 256 || !handler) return AE_BAD_PARAMETER;
|
|
|
|
if (acpiInterruptHandlers[interruptLevel]) {
|
|
return AE_ALREADY_EXISTS;
|
|
}
|
|
|
|
acpiInterruptHandlers[interruptLevel] = handler;
|
|
acpiInterruptContexts[interruptLevel] = context;
|
|
|
|
return KRegisterIRQ(interruptLevel, ACPIInterrupt, nullptr, "ACPICA") ? AE_OK : AE_ERROR;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsRemoveInterruptHandler(UINT32 interruptNumber, ACPI_OSD_HANDLER handler) {
|
|
if (interruptNumber > 256 || !handler) return AE_BAD_PARAMETER;
|
|
|
|
if (!acpiInterruptHandlers[interruptNumber]) {
|
|
return AE_NOT_EXIST;
|
|
}
|
|
|
|
if (handler != acpiInterruptHandlers[interruptNumber]) {
|
|
return AE_BAD_PARAMETER;
|
|
}
|
|
|
|
acpiInterruptHandlers[interruptNumber] = nullptr;
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS address, UINT64 *value, UINT32 width) {
|
|
KMutexAcquire(&acpicaPageBufferMutex);
|
|
EsDefer(KMutexRelease(&acpicaPageBufferMutex));
|
|
|
|
uintptr_t page = (uintptr_t) address & ~(K_PAGE_SIZE - 1);
|
|
uintptr_t offset = (uintptr_t) address & (K_PAGE_SIZE - 1);
|
|
|
|
PMRead(page, acpicaPageBuffer, 1);
|
|
|
|
if (width == 64) {
|
|
*value = *((uint64_t *) (acpicaPageBuffer + offset));
|
|
} else if (width == 32) {
|
|
*value = *((uint32_t *) (acpicaPageBuffer + offset));
|
|
} else if (width == 16) {
|
|
*value = *((uint16_t *) (acpicaPageBuffer + offset));
|
|
} else {
|
|
*value = acpicaPageBuffer[offset];
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS address, UINT64 value, UINT32 width) {
|
|
KMutexAcquire(&acpicaPageBufferMutex);
|
|
EsDefer(KMutexRelease(&acpicaPageBufferMutex));
|
|
|
|
uintptr_t page = (uintptr_t) address & ~(K_PAGE_SIZE - 1);
|
|
uintptr_t offset = (uintptr_t) address & (K_PAGE_SIZE - 1);
|
|
|
|
PMRead(page, acpicaPageBuffer, 1);
|
|
|
|
if (width == 64) {
|
|
*((uint64_t *) (acpicaPageBuffer + offset)) = value;
|
|
} else if (width == 32) {
|
|
*((uint32_t *) (acpicaPageBuffer + offset)) = value;
|
|
} else if (width == 16) {
|
|
*((uint16_t *) (acpicaPageBuffer + offset)) = value;
|
|
} else {
|
|
*((uint8_t *) (acpicaPageBuffer + offset)) = value;
|
|
}
|
|
|
|
PMCopy(page, acpicaPageBuffer, 1);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsReadPort(ACPI_IO_ADDRESS address, UINT32 *value, UINT32 width) {
|
|
// EsPrint("AcpiOsReadPort - %x, %d", address, width);
|
|
|
|
if (width == 8) {
|
|
*value = ProcessorIn8(address);
|
|
} else if (width == 16) {
|
|
*value = ProcessorIn16(address);
|
|
} else if (width == 32) {
|
|
*value = ProcessorIn32(address);
|
|
} else {
|
|
return AE_ERROR;
|
|
}
|
|
|
|
// EsPrint(" - %x\n", *value);
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsWritePort(ACPI_IO_ADDRESS address, UINT32 value, UINT32 width) {
|
|
// EsPrint("AcpiOsWritePort - %x, %x, %d", address, value, width);
|
|
|
|
if (width == 8) {
|
|
ProcessorOut8(address, (uint8_t) value);
|
|
} else if (width == 16) {
|
|
ProcessorOut16(address, (uint16_t) value);
|
|
} else if (width == 32) {
|
|
ProcessorOut32(address, (uint32_t) value);
|
|
} else {
|
|
return AE_ERROR;
|
|
}
|
|
|
|
// EsPrint(" - ;;\n");
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsReadPciConfiguration(ACPI_PCI_ID *address, UINT32 reg, UINT64 *value, UINT32 width) {
|
|
if (width == 64) {
|
|
uint64_t x = (uint64_t) KPCIReadConfig(address->Bus, address->Device, address->Function, reg)
|
|
| ((uint64_t) KPCIReadConfig(address->Bus, address->Device, address->Function, reg + 4) << 32);
|
|
*value = x;
|
|
} else {
|
|
uint32_t x = KPCIReadConfig(address->Bus, address->Device, address->Function, reg & ~3);
|
|
x >>= (reg & 3) * 8;
|
|
|
|
if (width == 8) x &= 0xFF;
|
|
if (width == 16) x &= 0xFFFF;
|
|
|
|
*value = x;
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsWritePciConfiguration(ACPI_PCI_ID *address, UINT32 reg, UINT64 value, UINT32 width) {
|
|
if (width == 64) {
|
|
KPCIWriteConfig(address->Bus, address->Device, address->Function, reg, value);
|
|
KPCIWriteConfig(address->Bus, address->Device, address->Function, reg + 4, value >> 32);
|
|
} else if (width == 32) {
|
|
KPCIWriteConfig(address->Bus, address->Device, address->Function, reg, value);
|
|
} else {
|
|
uint32_t x = KPCIReadConfig(address->Bus, address->Device, address->Function, reg & ~3);
|
|
uint32_t o = reg & 3;
|
|
|
|
if (width == 16) {
|
|
if (o == 2) {
|
|
x = (x & ~0xFFFF0000) | (value << 16);
|
|
} else {
|
|
x = (x & ~0x0000FFFF) | (value << 0);
|
|
}
|
|
} else if (width == 8) {
|
|
if (o == 3) {
|
|
x = (x & ~0xFF000000) | (value << 24);
|
|
} else if (o == 2) {
|
|
x = (x & ~0x00FF0000) | (value << 16);
|
|
} else if (o == 1) {
|
|
x = (x & ~0x0000FF00) | (value << 8);
|
|
} else {
|
|
x = (x & ~0x000000FF) | (value << 0);
|
|
}
|
|
}
|
|
|
|
KPCIWriteConfig(address->Bus, address->Device, address->Function, reg & ~3, x);
|
|
}
|
|
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C void AcpiOsPrintf(const char *format, ...) {
|
|
va_list arguments;
|
|
va_start(arguments, format);
|
|
int x = stbsp_vsnprintf(acpiPrintf, sizeof(acpiPrintf), format, arguments);
|
|
EsPrint("%s", x, acpiPrintf);
|
|
va_end(arguments);
|
|
}
|
|
|
|
ES_EXTERN_C void AcpiOsVprintf(const char *format, va_list arguments) {
|
|
int x = stbsp_vsnprintf(acpiPrintf, sizeof(acpiPrintf), format, arguments);
|
|
EsPrint("%s", x, acpiPrintf);
|
|
}
|
|
|
|
ES_EXTERN_C UINT64 AcpiOsGetTimer() {
|
|
uint64_t tick = ProcessorReadTimeStamp();
|
|
uint64_t ticksPerMs = timeStampTicksPerMs;
|
|
uint64_t ticksPer100Ns = ticksPerMs / 1000 / 10;
|
|
if (ticksPer100Ns == 0) return tick;
|
|
return tick / ticksPer100Ns;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsSignal(UINT32 function, void *information) {
|
|
(void) function;
|
|
(void) information;
|
|
KernelPanic("AcpiOsSignal - ACPI requested kernel panic.\n");
|
|
return AE_OK;
|
|
}
|
|
|
|
ES_EXTERN_C ACPI_STATUS AcpiOsEnterSleep(UINT8 sleepState, UINT32 registerAValue, UINT32 registerBValue) {
|
|
(void) sleepState;
|
|
(void) registerAValue;
|
|
(void) registerBValue;
|
|
return AE_OK;
|
|
}
|
|
|
|
UINT32 ACPIPowerButtonPressed(void *) {
|
|
KRegisterAsyncTask(&powerButtonAsyncTask, [] (KAsyncTask *) {
|
|
KKeyPress(ES_SCANCODE_ACPI_POWER | K_SCANCODE_KEY_PRESSED);
|
|
KKeyPress(ES_SCANCODE_ACPI_POWER | K_SCANCODE_KEY_RELEASED);
|
|
});
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t ACPIFindIRQ(ACPI_HANDLE object) {
|
|
ACPI_BUFFER buffer = {};
|
|
ACPI_STATUS status = AcpiGetCurrentResources(object, &buffer);
|
|
if (status != AE_BUFFER_OVERFLOW) return -1;
|
|
buffer.Pointer = EsHeapAllocate(buffer.Length, false, K_FIXED);
|
|
EsDefer(EsHeapFree(buffer.Pointer, buffer.Length, K_FIXED));
|
|
if (!buffer.Pointer) return -1;
|
|
status = AcpiGetCurrentResources(object, &buffer);
|
|
if (status != AE_OK) return -1;
|
|
ACPI_RESOURCE *resource = (ACPI_RESOURCE *) buffer.Pointer;
|
|
|
|
while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG) {
|
|
if (resource->Type == ACPI_RESOURCE_TYPE_IRQ) {
|
|
if (resource->Data.Irq.InterruptCount) {
|
|
return resource->Data.Irq.Interrupts[0];
|
|
}
|
|
} else if (resource->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
|
|
if (resource->Data.ExtendedIrq.InterruptCount) {
|
|
return resource->Data.ExtendedIrq.Interrupts[0];
|
|
}
|
|
}
|
|
|
|
resource = (ACPI_RESOURCE *) ((uint8_t *) resource + resource->Length);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void ACPIEnumeratePRTEntries(ACPI_HANDLE pciBus) {
|
|
// TODO Other PCI buses.
|
|
// TODO Is this always bus 0?
|
|
|
|
ACPI_BUFFER buffer = {};
|
|
ACPI_STATUS status = AcpiGetIrqRoutingTable(pciBus, &buffer);
|
|
if (status != AE_BUFFER_OVERFLOW) return;
|
|
buffer.Pointer = EsHeapAllocate(buffer.Length, false, K_FIXED);
|
|
EsDefer(EsHeapFree(buffer.Pointer, buffer.Length, K_FIXED));
|
|
if (!buffer.Pointer) return;
|
|
status = AcpiGetIrqRoutingTable(pciBus, &buffer);
|
|
if (status != AE_OK) return;
|
|
ACPI_PCI_ROUTING_TABLE *table = (ACPI_PCI_ROUTING_TABLE *) buffer.Pointer;
|
|
|
|
while (table->Length) {
|
|
ACPI_HANDLE source;
|
|
|
|
if (AE_OK == AcpiGetHandle(pciBus, table->Source, &source)) {
|
|
int32_t irq = ACPIFindIRQ(source);
|
|
|
|
if (irq != -1) {
|
|
KernelLog(LOG_INFO, "ACPI", "PRT entry", "Pin: %d; PCI slot: %X; IRQ: %d\n",
|
|
table->Pin, (table->Address >> 16) & 0xFF, irq);
|
|
|
|
if (irq != 9 && irq != 10 && irq != 11) {
|
|
KernelLog(LOG_ERROR, "ACPI", "unexpected IRQ", "IRQ %d was unexpected; expected values are 9, 10 or 11.\n", irq);
|
|
} else if ((table->Address >> 16) > 0xFF) {
|
|
KernelLog(LOG_ERROR, "ACPI", "unexpected address", "Address %x was larger than expected.\n", table->Address);
|
|
} else if (table->Pin > 3) {
|
|
KernelLog(LOG_ERROR, "ACPI", "unexpected pin", "Pin %d was larger than expected.\n", table->Pin);
|
|
} else {
|
|
ArchSetPCIIRQLine(table->Address >> 16, table->Pin, irq);
|
|
}
|
|
}
|
|
}
|
|
|
|
table = (ACPI_PCI_ROUTING_TABLE *) ((uint8_t *) table + table->Length);
|
|
}
|
|
}
|
|
|
|
struct KACPIObject : KDevice {
|
|
ACPI_HANDLE handle;
|
|
KACPINotificationHandler notificationHandler;
|
|
EsGeneric notificationHandlerContext;
|
|
};
|
|
|
|
void ACPINotificationHandler(ACPI_HANDLE, uint32_t value, void *context) {
|
|
KernelLog(LOG_INFO, "ACPI", "notification", "Received a notification with value %X.\n", value);
|
|
KACPIObject *object = (KACPIObject *) context;
|
|
object->notificationHandler(object, value, object->notificationHandlerContext);
|
|
}
|
|
|
|
EsError KACPIObjectSetDeviceNotificationHandler(KACPIObject *object, KACPINotificationHandler handler, EsGeneric context) {
|
|
object->notificationHandler = handler;
|
|
object->notificationHandlerContext = context;
|
|
ACPI_STATUS status = AcpiInstallNotifyHandler(object->handle, ACPI_DEVICE_NOTIFY, ACPINotificationHandler, object);
|
|
if (status == AE_OK) return ES_SUCCESS;
|
|
else if (status == AE_NO_MEMORY) return ES_ERROR_INSUFFICIENT_RESOURCES;
|
|
else return ES_ERROR_UNKNOWN;
|
|
}
|
|
|
|
EsError KACPIObjectEvaluateInteger(KACPIObject *object, const char *pathName, uint64_t *_integer) {
|
|
ACPI_BUFFER buffer = {};
|
|
buffer.Length = ACPI_ALLOCATE_BUFFER;
|
|
|
|
ACPI_STATUS status = AcpiEvaluateObject(object->handle, (char *) pathName, nullptr, &buffer);
|
|
EsError error = ES_SUCCESS;
|
|
|
|
if (status == AE_OK) {
|
|
ACPI_OBJECT *result = (ACPI_OBJECT *) buffer.Pointer;
|
|
|
|
if (result->Type == ACPI_TYPE_INTEGER) {
|
|
if (_integer) {
|
|
*_integer = result->Integer.Value;
|
|
}
|
|
} else {
|
|
error = ES_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ACPI_FREE(buffer.Pointer);
|
|
} else if (status == AE_NO_MEMORY) {
|
|
error = ES_ERROR_INSUFFICIENT_RESOURCES;
|
|
} else if (status == AE_NOT_FOUND) {
|
|
error = ES_ERROR_FILE_DOES_NOT_EXIST;
|
|
} else {
|
|
error = ES_ERROR_UNKNOWN;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
EsError KACPIObjectEvaluateMethodWithInteger(KACPIObject *object, const char *pathName, uint64_t integer) {
|
|
ACPI_OBJECT argument = {};
|
|
argument.Type = ACPI_TYPE_INTEGER;
|
|
argument.Integer.Value = integer;
|
|
ACPI_OBJECT_LIST argumentList = {};
|
|
argumentList.Count = 1;
|
|
argumentList.Pointer = &argument;
|
|
ACPI_STATUS status = AcpiEvaluateObject(object->handle, (char *) pathName, &argumentList, nullptr);
|
|
if (status == AE_OK) return ES_SUCCESS;
|
|
else if (status == AE_NO_MEMORY) return ES_ERROR_INSUFFICIENT_RESOURCES;
|
|
else if (status == AE_NOT_FOUND) return ES_ERROR_FILE_DOES_NOT_EXIST;
|
|
else return ES_ERROR_UNKNOWN;
|
|
}
|
|
|
|
ACPI_STATUS ACPIWalkNamespaceCallback(ACPI_HANDLE object, uint32_t depth, void *, void **) {
|
|
ACPI_DEVICE_INFO *information;
|
|
AcpiGetObjectInfo(object, &information);
|
|
|
|
char name[5];
|
|
EsMemoryCopy(name, &information->Name, 4);
|
|
name[4] = 0;
|
|
|
|
if (information->Type == ACPI_TYPE_DEVICE) {
|
|
KernelLog(LOG_INFO, "ACPI", "device object", "Found device object '%z' at depth %d with HID '%z', UID '%z' and address %x.\n",
|
|
name, depth,
|
|
(information->Valid & ACPI_VALID_HID) ? information->HardwareId.String : "??",
|
|
(information->Valid & ACPI_VALID_UID) ? information->UniqueId.String : "??",
|
|
(information->Valid & ACPI_VALID_ADR) ? information->Address : 0);
|
|
}
|
|
|
|
if (information->Type == ACPI_TYPE_THERMAL) {
|
|
KACPIObject *device = (KACPIObject *) KDeviceCreate("ACPI object", acpi.computer, sizeof(KACPIObject));
|
|
|
|
if (device) {
|
|
device->handle = object;
|
|
KDeviceAttachByName(device, "ACPIThermal");
|
|
}
|
|
}
|
|
|
|
ACPI_FREE(information);
|
|
return AE_OK;
|
|
}
|
|
|
|
void ArchShutdown() {
|
|
if (shutdownAction == ES_SHUTDOWN_ACTION_RESTART) ProcessorReset();
|
|
AcpiEnterSleepStatePrep(5);
|
|
ProcessorDisableInterrupts();
|
|
AcpiEnterSleepState(5);
|
|
}
|
|
|
|
void ACPICAInitialise() {
|
|
AcpiInitializeSubsystem();
|
|
AcpiInitializeTables(nullptr, 256, true);
|
|
AcpiLoadTables();
|
|
AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
|
|
AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
|
|
|
|
if (AE_OK == AcpiEnableEvent(ACPI_EVENT_POWER_BUTTON, 0)
|
|
&& AE_OK == AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, ACPIPowerButtonPressed, nullptr)) {
|
|
KDeviceCreate("ACPI power button", acpi.computer, sizeof(KDevice));
|
|
}
|
|
|
|
void *result;
|
|
AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 10, ACPIWalkNamespaceCallback, nullptr, nullptr, &result);
|
|
|
|
ACPI_HANDLE pciBus;
|
|
char pciBusPath[] = "\\_SB_.PCI0";
|
|
|
|
if (AE_OK == AcpiGetHandle(nullptr, pciBusPath, &pciBus)) {
|
|
ACPIEnumeratePRTEntries(pciBus);
|
|
}
|
|
}
|