diff --git a/apps/system_monitor.cpp b/apps/system_monitor.cpp index c789549..a50f567 100644 --- a/apps/system_monitor.cpp +++ b/apps/system_monitor.cpp @@ -401,6 +401,12 @@ void ProcessApplicationMessage(EsMessage *message) { AddTab(toolbar, DISPLAY_PROCESSES, "Processes", true); AddTab(toolbar, DISPLAY_GENERAL_LOG, "System log"); AddTab(toolbar, DISPLAY_MEMORY, "Memory"); + + EsSpacerCreate(toolbar, ES_CELL_H_FILL); + + EsButtonOnCommand(EsButtonCreate(toolbar, ES_FLAGS_DEFAULT, 0, "Shutdown"), [] (Instance *, EsElement *, EsCommand *) { + EsSystemShowShutdownDialog(); + }); } else if (message->type == ES_MSG_INSTANCE_DESTROY) { processes.Free(); } diff --git a/desktop/gui.cpp b/desktop/gui.cpp index a8eaf9c..f6771eb 100644 --- a/desktop/gui.cpp +++ b/desktop/gui.cpp @@ -1441,7 +1441,6 @@ void EsElement::InternalPaint(EsPainter *painter, int paintFlags) { } if (state & UI_STATE_INSPECTING) EsPerformanceTimerPush(); - double timeChildPaint = 0; // Get the interpolated style. @@ -1557,8 +1556,6 @@ void EsElement::InternalPaint(EsPainter *painter, int paintFlags) { // Paint the children. // TODO Optimisation: don't paint children overlapped by an opaque sibling. - if (state & UI_STATE_INSPECTING) EsPerformanceTimerPush(); - m.type = ES_MSG_PAINT_CHILDREN; m.painter = painter; @@ -1627,8 +1624,6 @@ void EsElement::InternalPaint(EsPainter *painter, int paintFlags) { zOrder.type = ES_MSG_AFTER_Z_ORDER; EsMessageSend(this, &zOrder); } - - if (state & UI_STATE_INSPECTING) timeChildPaint = EsPerformanceTimerPop() * 1000; } // Let the inspector draw some decorations over the element. @@ -1637,11 +1632,6 @@ void EsElement::InternalPaint(EsPainter *painter, int paintFlags) { InspectorNotifyElementPainted(this, painter); } - if (state & UI_STATE_INSPECTING) { - double timeTotalPaint = EsPerformanceTimerPop() * 1000; - InspectorNotifyElementEvent(this, "paint", "Paint in %Fms (%Fms with children).", timeTotalPaint - timeChildPaint, timeTotalPaint); - } - *painter = oldPainter; if (window->visualizePaintSteps && ES_RECT_VALID(window->updateRegionInProgress) && painter->target->forWindowManager) { diff --git a/desktop/text.cpp b/desktop/text.cpp index 977b871..a1f68d7 100644 --- a/desktop/text.cpp +++ b/desktop/text.cpp @@ -2872,9 +2872,9 @@ Array TextApplySyntaxHighlighting(const EsTextStyle *baseStyle, int l // TODO Unicode grapheme/word boundaries. // TODO Selecting lines with the margin. -struct DocumentLine { - char *GetBuffer(EsTextbox *textbox); +#define GET_BUFFER(line) TextboxGetDocumentLineBuffer(textbox, line) +struct DocumentLine { int32_t lengthBytes, lengthWidth, height, @@ -3295,11 +3295,11 @@ void TextboxUpdateCommands(EsTextbox *textbox, bool noClipboard) { } } -char *DocumentLine::GetBuffer(EsTextbox *textbox) { - if (textbox->activeLineIndex == this - textbox->lines.array) { +char *TextboxGetDocumentLineBuffer(EsTextbox *textbox, DocumentLine *line) { + if (textbox->activeLineIndex == line - textbox->lines.array) { return textbox->activeLine; } else { - return textbox->data + offset; + return textbox->data + line->offset; } } @@ -3358,7 +3358,7 @@ void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter) { int scrollX = textbox->scroll.position[0]; int viewportWidth = bounds.r; int caretX = TextGetPartialStringWidth(textbox, &textbox->textStyle, - line->GetBuffer(textbox), line->lengthBytes, caret.byte) - scrollX + textbox->insets.l; + GET_BUFFER(line), line->lengthBytes, caret.byte) - scrollX + textbox->insets.l; if (caretX < textbox->insets.l) { scrollX += caretX - textbox->insets.l; @@ -3386,7 +3386,7 @@ bool TextboxMoveCaret(EsTextbox *textbox, TextboxCaret *caret, bool right, int m if (textbox->verticalMotionHorizontalDepth == -1) { textbox->verticalMotionHorizontalDepth = TextGetPartialStringWidth(textbox, &textbox->textStyle, - textbox->lines[caret->line].GetBuffer(textbox), textbox->lines[caret->line].lengthBytes, caret->byte); + GET_BUFFER(&textbox->lines[caret->line]), textbox->lines[caret->line].lengthBytes, caret->byte); } if (right) caret->line++; else caret->line--; @@ -3395,11 +3395,11 @@ bool TextboxMoveCaret(EsTextbox *textbox, TextboxCaret *caret, bool right, int m DocumentLine *line = &textbox->lines[caret->line]; int pointX = textbox->verticalMotionHorizontalDepth ? textbox->verticalMotionHorizontalDepth - 1 : 0; ptrdiff_t result = TextGetCharacterAtPoint(textbox, &textbox->textStyle, - line->GetBuffer(textbox), line->lengthBytes, &pointX, ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE); + GET_BUFFER(line), line->lengthBytes, &pointX, ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE); caret->byte = result == -1 ? line->lengthBytes : result; } else { CharacterType type = CHARACTER_INVALID; - char *currentLineBuffer = textbox->lines[caret->line].GetBuffer(textbox); + char *currentLineBuffer = GET_BUFFER(&textbox->lines[caret->line]); if (moveType == MOVE_CARET_WORD && right) goto checkCharacterType; while (true) { @@ -3409,7 +3409,7 @@ bool TextboxMoveCaret(EsTextbox *textbox, TextboxCaret *caret, bool right, int m caret->byte = utf8_retreat(currentLineBuffer + caret->byte) - currentLineBuffer; } else { caret->byte = textbox->lines[--caret->line].lengthBytes; - currentLineBuffer = textbox->lines[caret->line].GetBuffer(textbox); + currentLineBuffer = GET_BUFFER(&textbox->lines[caret->line]); } } else { break; // We cannot move any further left. @@ -3421,7 +3421,7 @@ bool TextboxMoveCaret(EsTextbox *textbox, TextboxCaret *caret, bool right, int m } else { caret->line++; caret->byte = 0; - currentLineBuffer = textbox->lines[caret->line].GetBuffer(textbox); + currentLineBuffer = GET_BUFFER(&textbox->lines[caret->line]); } } else { break; // We cannot move any further right. @@ -3543,7 +3543,7 @@ void TextboxRefreshVisibleLines(EsTextbox *textbox, bool repaint = true) { } line->lengthWidth = TextGetStringWidth(textbox, &textbox->textStyle, - line->GetBuffer(textbox), line->lengthBytes); + GET_BUFFER(line), line->lengthBytes); if (textbox->longestLine != -1 && line->lengthWidth > textbox->longestLineWidth) { textbox->longestLine = textbox->firstVisibleLine + i; @@ -4016,7 +4016,7 @@ char *EsTextboxGetContents(EsTextbox *textbox, size_t *_bytes, uint32_t flags) { } } - EsMemoryCopy(buffer + position, line->GetBuffer(textbox) + offsetFrom, offsetTo - offsetFrom); + EsMemoryCopy(buffer + position, GET_BUFFER(line) + offsetFrom, offsetTo - offsetFrom); position += offsetTo - offsetFrom; if (includeNewline && i != lineTo) { @@ -4058,7 +4058,7 @@ bool EsTextboxFind(EsTextbox *textbox, const char *needle, intptr_t _needleBytes while (true) { DocumentLine *line = &textbox->lines[lineIndex]; - const char *buffer = line->GetBuffer(textbox); + const char *buffer = GET_BUFFER(line); size_t bufferBytes = line->lengthBytes; EsAssert(byteIndex <= bufferBytes); // Invalid find byte offset. @@ -4174,7 +4174,7 @@ bool TextboxFindCaret(EsTextbox *textbox, int positionX, int positionY, bool sec int pointX = positionX + textbox->scroll.position[0] - textbox->insets.l; if (pointX < 0) pointX = 0; ptrdiff_t result = TextGetCharacterAtPoint(textbox, &textbox->textStyle, - line->GetBuffer(textbox), line->lengthBytes, + GET_BUFFER(line), line->lengthBytes, &pointX, ES_TEXT_GET_CHARACTER_AT_POINT_MIDDLE); textbox->carets[1].byte = result == -1 ? line->lengthBytes : result; } @@ -4359,7 +4359,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { if (textbox->syntaxHighlightingLanguage && line->lengthBytes) { if (textRuns.Length()) textRuns.SetLength(0); textRuns = TextApplySyntaxHighlighting(&textbox->textStyle, textbox->syntaxHighlightingLanguage, - textbox->syntaxHighlightingColors, textRuns, line->GetBuffer(textbox), line->lengthBytes); + textbox->syntaxHighlightingColors, textRuns, GET_BUFFER(line), line->lengthBytes); } else { textRuns.SetLength(2); textRuns[0].style = textbox->textStyle; @@ -4376,7 +4376,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { if (!textRuns.Length()) { plan = nullptr; } else if (textRuns[1].offset) { - plan = EsTextPlanCreate(element, &properties, lineBounds, line->GetBuffer(textbox), textRuns.array, textRuns.Length() - 1); + plan = EsTextPlanCreate(element, &properties, lineBounds, GET_BUFFER(line), textRuns.array, textRuns.Length() - 1); } else { textRuns[1].offset = 1; // Make sure that the caret and selection is draw correctly, even on empty lines. plan = EsTextPlanCreate(element, &properties, lineBounds, " ", textRuns.array, textRuns.Length() - 1); @@ -4467,6 +4467,10 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { textbox->Repaint(true); verticalMotion = true; } else if (message->keyboard.scancode == ES_SCANCODE_BACKSPACE || message->keyboard.scancode == ES_SCANCODE_DELETE) { + if (!textbox->editing) { + EsTextboxStartEdit(textbox); + } + if (!TextboxCompareCarets(textbox->carets + 0, textbox->carets + 1)) { TextboxMoveCaret(textbox, textbox->carets + 1, message->keyboard.scancode == ES_SCANCODE_BACKSPACE ? MOVE_CARET_BACKWARDS : MOVE_CARET_FORWARDS, ctrl ? MOVE_CARET_WORD : MOVE_CARET_SINGLE); @@ -4495,7 +4499,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { if (inputString && (message->keyboard.modifiers & ~(ES_MODIFIER_SHIFT | ES_MODIFIER_ALT_GR)) == 0) { if (textbox->smartQuotes && api.global->useSmartQuotes) { DocumentLine *currentLine = &textbox->lines[textbox->carets[0].line]; - const char *buffer = currentLine->GetBuffer(textbox); + const char *buffer = GET_BUFFER(currentLine); bool left = !textbox->carets[0].byte || buffer[textbox->carets[0].byte - 1] == ' '; if (inputString[0] == '"' && inputString[1] == 0) { @@ -4511,7 +4515,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { // Copy the indentation from the previous line. DocumentLine *previousLine = &textbox->lines[textbox->carets[0].line - 1]; - const char *buffer = previousLine->GetBuffer(textbox); + const char *buffer = GET_BUFFER(previousLine); int32_t i = 0; for (; i < previousLine->lengthBytes; i++) { @@ -4609,7 +4613,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { if (selectionTo - selectionFrom == 7) { char buffer[7]; - EsMemoryCopy(buffer, textbox->lines[textbox->carets[0].line].GetBuffer(textbox) + selectionFrom, 7); + EsMemoryCopy(buffer, GET_BUFFER(&textbox->lines[textbox->carets[0].line]) + selectionFrom, 7); if (buffer[0] == '#' && EsCRTisxdigit(buffer[1]) && EsCRTisxdigit(buffer[2]) && EsCRTisxdigit(buffer[3]) && EsCRTisxdigit(buffer[4]) && EsCRTisxdigit(buffer[5]) && EsCRTisxdigit(buffer[6])) { @@ -4662,7 +4666,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { EsElementRepaintForScroll(textbox, message, EsRectangleAdd(element->GetInternalOffset(), element->style->borders)); } else if (message->type == ES_MSG_GET_INSPECTOR_INFORMATION) { DocumentLine *firstLine = &textbox->lines.First(); - EsBufferFormat(message->getContent.buffer, "'%s'", firstLine->lengthBytes, firstLine->GetBuffer(textbox)); + EsBufferFormat(message->getContent.buffer, "'%s'", firstLine->lengthBytes, GET_BUFFER(firstLine)); } else if (message->type == ES_MSG_UI_SCALE_CHANGED) { if (textbox->margin) { // Force the margin to update its style now, so that its width can be read correctly by TextboxStyleChanged. @@ -4960,6 +4964,8 @@ void EsTextboxEnableSmartQuotes(EsTextbox *textbox, bool enabled) { textbox->smartQuotes = enabled; } +#undef GET_BUFFER + // --------------------------------- Text displays. // TODO Inline images and icons. diff --git a/drivers/acpi.cpp b/drivers/acpi.cpp index 0463544..3d87b0f 100644 --- a/drivers/acpi.cpp +++ b/drivers/acpi.cpp @@ -1,6 +1,3 @@ -// TODO ACPICA initialisation hangs on my computer when SMP is enabled when it tries to write to IO port 0xB2 (power management, generates SMI). -// This is possibly related to the hang when writing to the keyboard controller IO ports that only occurs with SMP enabled. - #define SIGNATURE_RSDP (0x2052545020445352) #define SIGNATURE_RSDT (0x54445352) @@ -418,6 +415,7 @@ ES_EXTERN_C void AcpiOsReleaseLock(ACPI_SPINLOCK handle, ACPI_CPU_FLAGS flags) { KSpinlockRelease(spinlock); } +// TODO Can these arrays be made smaller? ACPI_OSD_HANDLER acpiInterruptHandlers[256]; void *acpiInterruptContexts[256]; @@ -721,6 +719,100 @@ void ACPIEnumeratePRTEntries(ACPI_HANDLE pciBus) { 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; +} #endif void ACPIInitialise2() { @@ -728,8 +820,6 @@ void ACPIInitialise2() { AcpiInitializeSubsystem(); AcpiInitializeTables(nullptr, 256, true); AcpiLoadTables(); - ProcessorDisableInterrupts(); - ProcessorEnableInterrupts(); AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); AcpiInitializeObjects(ACPI_FULL_INITIALIZATION); @@ -739,23 +829,7 @@ void ACPIInitialise2() { } void *result; - - AcpiGetDevices(nullptr, [] (ACPI_HANDLE object, uint32_t, void *, void **) -> ACPI_STATUS { - ACPI_DEVICE_INFO *information; - AcpiGetObjectInfo(object, &information); - - char name[5]; - EsMemoryCopy(name, &information->Name, 4); - name[4] = 0; - - KernelLog(LOG_INFO, "ACPI", "device object", "Found device object '%z' with HID '%z', UID '%z' and address %x.\n", - name, (information->Valid & ACPI_VALID_HID) ? information->HardwareId.String : "??", - (information->Valid & ACPI_VALID_UID) ? information->UniqueId.String : "??", - (information->Valid & ACPI_VALID_ADR) ? information->Address : 0); - - ACPI_FREE(information); - return AE_OK; - }, nullptr, &result); + AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 10, ACPIWalkNamespaceCallback, nullptr, nullptr, &result); ACPI_HANDLE pciBus; char pciBusPath[] = "\\_SB_.PCI0"; diff --git a/drivers/acpi_thermal.cpp b/drivers/acpi_thermal.cpp new file mode 100644 index 0000000..ee38a34 --- /dev/null +++ b/drivers/acpi_thermal.cpp @@ -0,0 +1,98 @@ +#include + +// TODO Active cooling. +// TODO Passive cooling. +// TODO Temperature change polling. +// TODO Refresh temperature/thresholds on a separate thread. + +struct ACPIThermalZone : KDevice { + KACPIObject *object; + uint64_t criticalThreshold; // Once reached, the system should shutdown as quickly as possible. + uint64_t hotThreshold; // Once reached, the system will likely want to enter sleep mode. + uint64_t passiveThreshold; // Once reached, the passive cooling algorithm (e.g. processor speed throttling) should be enabled. + uint64_t activeThresholds[10]; // Once reached, the given active cooling device (e.g. fan) should be enabled. + uint64_t pollingFrequency; // Recommended polling frequency of temperature, in tenths of a seconds. + uint64_t currentTemperature; + KMutex refreshMutex; +}; + +static void ACPIThermalRefreshTemperature(EsGeneric context) { + ACPIThermalZone *device = (ACPIThermalZone *) context.p; + KACPIObject *object = device->object; + KMutexAcquire(&device->refreshMutex); + KernelLog(LOG_INFO, "ACPIThermal", "temperature", "Taking temperature reading...\n"); + + EsError error = KACPIObjectEvaluateInteger(object, "_TMP", &device->currentTemperature); + if (error == ES_SUCCESS) KernelLog(LOG_INFO, "ACPIThermal", "temperature", "Current temperature: %d K.\n", device->currentTemperature / 10); + else KernelLog(LOG_ERROR, "ACPIThermal", "temperature", "Unable to read current temperature (%d).\n", error); + + // TODO Active cooling. + + KMutexRelease(&device->refreshMutex); +} + +static void ACPIThermalRefreshThresholds(EsGeneric context) { + ACPIThermalZone *device = (ACPIThermalZone *) context.p; + KACPIObject *object = device->object; + KMutexAcquire(&device->refreshMutex); + KernelLog(LOG_INFO, "ACPIThermal", "threshold", "Taking threshold readings...\n"); + + EsError error; + + error = KACPIObjectEvaluateInteger(object, "_CRT", &device->criticalThreshold); + if (error == ES_SUCCESS) KernelLog(LOG_INFO, "ACPIThermal", "threshold", "Critical temperature threshold: %d K.\n", device->criticalThreshold / 10); + + error = KACPIObjectEvaluateInteger(object, "_HOT", &device->hotThreshold); + if (error == ES_SUCCESS) KernelLog(LOG_INFO, "ACPIThermal", "threshold", "Hot temperature threshold: %d K.\n", device->hotThreshold / 10); + + error = KACPIObjectEvaluateInteger(object, "_PSV", &device->passiveThreshold); + if (error == ES_SUCCESS) KernelLog(LOG_INFO, "ACPIThermal", "threshold", "Passive temperature threshold: %d K.\n", device->passiveThreshold / 10); + + error = KACPIObjectEvaluateInteger(object, "_TZP", &device->passiveThreshold); + if (error == ES_SUCCESS) KernelLog(LOG_INFO, "ACPIThermal", "threshold", "Recommended polling frequency: %d s.\n", device->pollingFrequency / 10); + + char name[5] = "_AC0"; + + for (uintptr_t i = 0; i <= 9; i++, name[3]++) { + EsError error = KACPIObjectEvaluateInteger(object, name, &device->activeThresholds[i]); + if (error == ES_SUCCESS) KernelLog(LOG_INFO, "ACPIThermal", "threshold", "Active temperature threshold %d: %d K.\n", i, device->activeThresholds[i] / 10); + else break; + } + + KMutexRelease(&device->refreshMutex); + ACPIThermalRefreshTemperature(device); +} + +static void ACPIThermalDeviceNotificationHandler(KACPIObject *, uint32_t value, EsGeneric context) { + ACPIThermalZone *device = (ACPIThermalZone *) context.p; + + if (value == 0x80) { + KRegisterAsyncTask(ACPIThermalRefreshTemperature, device); + } else if (value == 0x81) { + KRegisterAsyncTask(ACPIThermalRefreshThresholds, device); + } +} + +static void ACPIThermalDeviceAttach(KDevice *parent) { + KACPIObject *object = (KACPIObject *) parent; + ACPIThermalZone *device = (ACPIThermalZone *) KDeviceCreate("ACPI thermal zone", parent, sizeof(ACPIThermalZone)); + if (!device) return; + device->object = object; + KernelLog(LOG_INFO, "ACPIThermal", "device attached", "Found ACPI thermal zone.\n"); + + ACPIThermalRefreshThresholds(device); + + EsError error; + + error = KACPIObjectSetDeviceNotificationHandler(object, ACPIThermalDeviceNotificationHandler, device); + if (error == ES_SUCCESS) KernelLog(LOG_INFO, "ACPIThermal", "notification handler", "Successfully installed notification handler.\n"); + else KernelLog(LOG_ERROR, "ACPIThermal", "notification handler", "Unable to install notification handler (%d).\n", error); + + error = KACPIObjectEvaluateMethodWithInteger(object, "_SCP", 0 /* active cooling policy */); + if (error == ES_SUCCESS) KernelLog(LOG_INFO, "ACPIThermal", "cooling policy", "Successfully set active cooling policy.\n"); + else KernelLog(LOG_ERROR, "ACPIThermal", "cooling policy", "Unable to set active cooling policy (%d).\n", error); +} + +KDriver driverACPIThermal = { + .attach = ACPIThermalDeviceAttach, +}; diff --git a/kernel/config.ini b/kernel/config.ini index 0612bc9..76241d7 100644 --- a/kernel/config.ini +++ b/kernel/config.ini @@ -149,3 +149,9 @@ builtin=1 parent=Files signature_offset=1080 signature=Sī + +; ACPI devices. + +[@driver ACPIThermal] +source=drivers/acpi_thermal.cpp +builtin=1 diff --git a/kernel/module.h b/kernel/module.h index d0d708b..9c396de 100644 --- a/kernel/module.h +++ b/kernel/module.h @@ -1056,3 +1056,13 @@ void KRegisterNetInterface(NetInterface *interface); void NetInterfaceReceive(NetInterface *interface, const uint8_t *data, size_t dataBytes, NetPacketType packetType); // NOTE Currently this can be only called on one thread for each NetInterface. (This restriction will hopefully be removed soon.) void NetInterfaceSetConnected(NetInterface *interface, bool connected); // NOTE This shouldn't be called by more than one thread. void NetInterfaceShutdown(NetInterface *interface); // NOTE This doesn't do any disconnecting/cancelling of tasks. Currently it only sends a DHCP request to release the IP address, and is expected to be called at the final stages of system shutdown. + +// --------------------------------------------------------------------------------------------------------------- +// ACPI. +// --------------------------------------------------------------------------------------------------------------- + +struct KACPIObject; +typedef void (*KACPINotificationHandler)(KACPIObject *object, uint32_t value, EsGeneric context); +EsError KACPIObjectEvaluateInteger(KACPIObject *object, const char *pathName, uint64_t *_integer); +EsError KACPIObjectEvaluateMethodWithInteger(KACPIObject *object, const char *pathName, uint64_t integer); +EsError KACPIObjectSetDeviceNotificationHandler(KACPIObject *object, KACPINotificationHandler handler, EsGeneric context); diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index 21f6451..4f602ac 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -1848,18 +1848,22 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_DEVICE_CONTROL) { } SYSCALL_IMPLEMENT(ES_SYSCALL_DEBUG_COMMAND) { -#ifdef DEBUG_BUILD - if (argument0 == 1) { - ArchResetCPU(); - } else if (argument0 == 2) { - KernelPanic("Debug command 2.\n"); - } else if (argument0 == 3) { + if (argument0 == 3) { + SYSCALL_PERMISSION(ES_PERMISSION_TAKE_SYSTEM_SNAPSHOT); + // TODO Temporary: moved out of the DEBUG_BUILD block. extern char kernelLog[]; extern uintptr_t kernelLogPosition; size_t bytes = kernelLogPosition; if (argument2 < bytes) bytes = argument2; EsMemoryCopy((void *) argument1, kernelLog, bytes); SYSCALL_RETURN(bytes, false); + } + +#ifdef DEBUG_BUILD + if (argument0 == 1) { + ArchResetCPU(); + } else if (argument0 == 2) { + KernelPanic("Debug command 2.\n"); } else if (argument0 == 4) { SYSCALL_BUFFER(argument1, 1, 0, false); diff --git a/ports/mesa/obj_viewer.c b/ports/mesa/obj_viewer.c index 1a82c06..c10642d 100644 --- a/ports/mesa/obj_viewer.c +++ b/ports/mesa/obj_viewer.c @@ -10,6 +10,7 @@ #include #include #include +#include #define MODERN_GL @@ -75,6 +76,9 @@ static void (*glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLbo uint32_t framesDrawn; double lastTime; float timeMs; +float previousTimeMs; +double lastGLDuration; +double lastDrawBitmapDuration; int shaderTransform, shaderNormalTransform; size_t triangleCount, vertexCount; @@ -122,6 +126,13 @@ void Render() { return; } + if (previousTimeMs == timeMs) { + return; + } + + previousTimeMs = timeMs; + EsPerformanceTimerPush(); + glClearColor(0.21f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); #ifdef MODERN_GL @@ -151,13 +162,15 @@ void Render() { glEnd(); #endif glFinish(); -} -#include + framesDrawn++; + lastGLDuration = EsPerformanceTimerPop(); +} int CanvasCallback(EsElement *element, EsMessage *message) { if (message->type == ES_MSG_PAINT_BACKGROUND) { Render(); + EsPerformanceTimerPush(); EsRectangle bounds = EsPainterBoundsInset(message->painter); EsRectangle imageBounds = EsRectangleCenter(bounds, ES_RECT_2S(IMAGE_WIDTH, IMAGE_HEIGHT)); EsDrawBitmap(message->painter, imageBounds, buffer, IMAGE_WIDTH * 4, ES_DRAW_BITMAP_OPAQUE); @@ -165,19 +178,18 @@ int CanvasCallback(EsElement *element, EsMessage *message) { EsDrawBlock(message->painter, ES_RECT_4(imageBounds.r, bounds.r, bounds.t, bounds.b), 0xFF333336); EsDrawBlock(message->painter, ES_RECT_4(imageBounds.l, imageBounds.r, bounds.t, imageBounds.t), 0xFF333336); EsDrawBlock(message->painter, ES_RECT_4(imageBounds.l, imageBounds.r, imageBounds.b, bounds.b), 0xFF333336); - framesDrawn++; + lastDrawBitmapDuration = EsPerformanceTimerPop(); } else if (message->type == ES_MSG_ANIMATE) { double currentTime = EsTimeStampMs(); if (currentTime - lastTime > 1000.0) { - EsPrint("%d fps\n", framesDrawn); + EsPrint("%d fps (last frame: GL %F s, DrawBitmap %F s)\n", framesDrawn, lastGLDuration, lastDrawBitmapDuration); lastTime = currentTime; framesDrawn = 0; } message->animate.complete = false; timeMs += message->animate.deltaMs; - EsRectangle imageBounds = EsRectangleCenter(EsElementGetInsetBounds(element), ES_RECT_2S(IMAGE_WIDTH, IMAGE_HEIGHT)); EsElementRepaint(element, &imageBounds); diff --git a/res/Theme Source.dat b/res/Theme Source.dat index 0a47fb9..546cca0 100644 Binary files a/res/Theme Source.dat and b/res/Theme Source.dat differ diff --git a/res/Theme.dat b/res/Theme.dat index 51ebe3c..6264c35 100644 Binary files a/res/Theme.dat and b/res/Theme.dat differ diff --git a/util/build_common.h b/util/build_common.h index 1d71c65..4907a86 100644 --- a/util/build_common.h +++ b/util/build_common.h @@ -260,6 +260,7 @@ typedef struct Option { Option options[] = { { "Driver.ACPI", OPTION_TYPE_BOOL, { .b = true } }, + { "Driver.ACPIThermal", OPTION_TYPE_BOOL, { .b = true } }, { "Driver.AHCI", OPTION_TYPE_BOOL, { .b = true } }, { "Driver.BGA", OPTION_TYPE_BOOL, { .b = true } }, { "Driver.EssenceFS", OPTION_TYPE_BOOL, { .b = true } }, diff --git a/util/uefi_to_device.sh b/util/uefi_to_device.sh index e621526..29d000d 100755 --- a/util/uefi_to_device.sh +++ b/util/uefi_to_device.sh @@ -12,10 +12,19 @@ mkdir -p mount/EFI/BOOT cp bin/uefi mount/EFI/BOOT/BOOTX64.EFI cp bin/Kernel.esx mount/eskernel.esx cp bin/uefi_loader mount/esloader.bin -cp bin/iid.dat mount/esiid.dat + +if [ $# -eq 2 ]; then + cp bin/iid.dat mount/esiid.dat +fi + umount $1 rmdir mount +if [ $# -eq 1 ]; then + echo Skipping drive copy. + exit 0 +fi + SOURCE_OFFSET=`fdisk -l bin/drive | grep 'Linux' | awk '{print $3}'` SOURCE_COUNT=`fdisk -l bin/drive | grep 'Linux' | awk '{print $5}'` DESTINATION_COUNT=`blockdev --getsz $2`