~aleteoryx/muditaos

920db59b2e454f590ad3ebf74448ab4ca5010db3 — Maciej Gibowicz 2 years ago cbe1ed6
[BH-1791] Add CPU frequency lock during log dump

This will improve security and peripheral stabilization when downloading
logs to a file.
M harmony_changelog.md => harmony_changelog.md +1 -0
@@ 11,6 11,7 @@
* Fixed frequency lock during user activity
* Fixed possibility of OS crash during update package size check
* Fixed incorrect calculation of requested CPU frequency
* Fixed CPU frequency setting when dumping logs to a file

### Added
* Files not fully transferred via Center will be now removed when USB cable is unplugged

M module-sys/SystemManager/CMakeLists.txt => module-sys/SystemManager/CMakeLists.txt +1 -0
@@ 14,6 14,7 @@ target_sources(sys-manager
    PRIVATE
        CpuGovernor.cpp
        CpuSentinel.cpp
        LogSentinel.cpp
        GovernorSentinelOperations.cpp
        CpuStatistics.cpp
        TaskStatistics.cpp

A module-sys/SystemManager/LogSentinel.cpp => module-sys/SystemManager/LogSentinel.cpp +69 -0
@@ 0,0 1,69 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <SystemManager/LogSentinel.hpp>
#include <log/log.hpp>

namespace sys
{
    namespace
    {
        constexpr std::uint32_t holdMutexTimeoutMs{100000};
        constexpr auto sentinelName{"LoggerSentinel"};
        constexpr auto holdFrequencyReason{"LogDump"};
    } // namespace

    LogSentinel::LogSentinel(bsp::CpuFrequencyMHz frequencyToLock) : requestedFrequency(frequencyToLock)
    {
        mutex = xSemaphoreCreateMutex();
        if (mutex == NULL) {
            LOG_ERROR("Failed to create mutex for logger!");
        }
    }

    void LogSentinel::HoldMinimumFrequency()
    {
        frequencyRequest = true;
        if (mutex != NULL) {
            if (xSemaphoreTake(mutex, pdMS_TO_TICKS(holdMutexTimeoutMs)) != pdTRUE) {
                LOG_ERROR("Failed to get mutex for the logger!");
            }
        }
        frequencyRequest = false;
    }

    void LogSentinel::ReleaseMinimumFrequency()
    {
        if (mutex != NULL) {
            xSemaphoreGive(mutex);
        }
    }

    void LogSentinel::UpdateCurrentFrequency(bsp::CpuFrequencyMHz newFrequency)
    {
        const bool newPermission = newFrequency >= requestedFrequency;
        if (mutex != NULL && dumpPermission != newPermission) {
            if (newPermission) {
                xSemaphoreGive(mutex);
            }
            else if (xSemaphoreTake(mutex, 0) != pdTRUE) {
                LOG_ERROR("Failed to get mutex when reducing the CPU frequency!");
                return;
            }
        }
        dumpPermission = newPermission;
    }

    [[nodiscard]] auto LogSentinel::GetRequestedFrequency() const noexcept -> sentinel::View
    {
        sentinel::View view{.ownerTCBNumber = 0,
                            .name           = sentinelName,
                            .minFrequency   = (frequencyRequest ||
                                             ((mutex != NULL) && dumpPermission && (uxSemaphoreGetCount(mutex) == 0)))
                                                  ? requestedFrequency
                                                  : bsp::CpuFrequencyMHz::Level_0,
                            .reason         = holdFrequencyReason};
        return view;
    }

} // namespace sys

M module-sys/SystemManager/PowerManager.cpp => module-sys/SystemManager/PowerManager.cpp +16 -1
@@ 10,6 10,7 @@
#include <SystemManager/PowerManager.hpp>
#include <gsl/util>
#include <log/log.hpp>
#include <Logger.hpp>
#include <Utils.hpp>

namespace sys


@@ 19,6 20,8 @@ namespace sys
        constexpr auto lowestLevelName{"lowestCpuFrequency"};
        constexpr auto middleLevelName{"middleCpuFrequency"};
        constexpr auto highestLevelName{"highestCpuFrequency"};

        constexpr bsp::CpuFrequencyMHz logDumpFrequencyToHold{bsp::CpuFrequencyMHz::Level_4};
    } // namespace

    CpuFrequencyMonitor::CpuFrequencyMonitor(const std::string &name) : levelName(name)


@@ 60,6 63,9 @@ namespace sys
        driverSEMC      = drivers::DriverSEMC::Create(drivers::name::ExternalRAM);
        lowPowerControl = bsp::LowPowerMode::Create().value_or(nullptr);
        cpuGovernor     = std::make_unique<CpuGovernor>();
        logSentinel                       = std::make_unique<LogSentinel>(logDumpFrequencyToHold);
        Log::Logger::get().preDumpToFile  = [this]() { logSentinel->HoldMinimumFrequency(); };
        Log::Logger::get().postDumpToFile = [this]() { logSentinel->ReleaseMinimumFrequency(); };

        cpuAlgorithms = std::make_unique<cpu::AlgorithmFactory>();
        cpuAlgorithms->emplace(sys::cpu::AlgoID::ImmediateUpscale, std::make_unique<sys::cpu::ImmediateUpscale>());


@@ 107,7 113,7 @@ namespace sys
        uint32_t cpuLoad = cpuStatistics.GetPercentageCpuLoad();
        cpu::UpdateResult retval;
        const cpu::AlgorithmData data{
            cpuLoad, lowPowerControl->GetCurrentFrequencyLevel(), cpuGovernor->GetMinimumFrequencyRequested()};
            cpuLoad, lowPowerControl->GetCurrentFrequencyLevel(), GetMinimumCpuFrequencyRequested()};

        auto _ = gsl::finally([&retval, this, data] {
            retval.frequencySet = lowPowerControl->GetCurrentFrequencyLevel();


@@ 174,10 180,19 @@ namespace sys
        UpdateCpuFrequencyMonitor(lowPowerControl->GetCurrentFrequencyLevel());
        while (lowPowerControl->GetCurrentFrequencyLevel() != freq) {
            lowPowerControl->SetCpuFrequency(freq);
            logSentinel->UpdateCurrentFrequency(freq);
            cpuGovernor->InformSentinelsAboutCpuFrequencyChange(freq);
        }
    }

    [[nodiscard]] auto PowerManager::GetMinimumCpuFrequencyRequested() const noexcept -> sentinel::View
    {
        const auto governorSentinelsView = cpuGovernor->GetMinimumFrequencyRequested();
        const auto logSentinelView       = logSentinel->GetRequestedFrequency();
        return (logSentinelView.minFrequency > governorSentinelsView.minFrequency) ? logSentinelView
                                                                                   : governorSentinelsView;
    }

    [[nodiscard]] auto PowerManager::getExternalRamDevice() const noexcept -> std::shared_ptr<devices::Device>
    {
        return driverSEMC;

A module-sys/SystemManager/include/SystemManager/LogSentinel.hpp => module-sys/SystemManager/include/SystemManager/LogSentinel.hpp +29 -0
@@ 0,0 1,29 @@
// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <mutex.hpp>
#include <bsp/common.hpp>
#include "SentinelView.hpp"

namespace sys
{
    class LogSentinel
    {
      public:
        explicit LogSentinel(bsp::CpuFrequencyMHz frequencyToLock);

        void HoldMinimumFrequency();
        void ReleaseMinimumFrequency();
        void UpdateCurrentFrequency(bsp::CpuFrequencyMHz newFrequency);
        [[nodiscard]] auto GetRequestedFrequency() const noexcept -> sentinel::View;

      private:
        xSemaphoreHandle mutex;
        bsp::CpuFrequencyMHz requestedFrequency{bsp::CpuFrequencyMHz::Level_0};
        bool dumpPermission{true};
        bool frequencyRequest{false};
    };

} // namespace sys

M module-sys/SystemManager/include/SystemManager/PowerManager.hpp => module-sys/SystemManager/include/SystemManager/PowerManager.hpp +3 -0
@@ 9,6 9,7 @@
#include "drivers/semc/DriverSEMC.hpp"
#include "SysCpuUpdateResult.hpp"
#include "CpuGovernor.hpp"
#include "LogSentinel.hpp"
#include "TaskStatistics.hpp"
#include <bsp/lpm/PowerProfile.hpp>
#include <vector>


@@ 75,6 76,7 @@ namespace sys
        void SetCpuFrequency(bsp::CpuFrequencyMHz freq);

        void UpdateCpuFrequencyMonitor(bsp::CpuFrequencyMHz currentFreq);
        [[nodiscard]] auto GetMinimumCpuFrequencyRequested() const noexcept -> sentinel::View;

        TickType_t lastCpuFrequencyChangeTimestamp{0};
        TickType_t lastLogStatisticsTimestamp{0};


@@ 84,6 86,7 @@ namespace sys
        std::shared_ptr<drivers::DriverSEMC> driverSEMC;
        std::unique_ptr<bsp::LowPowerMode> lowPowerControl;
        std::unique_ptr<CpuGovernor> cpuGovernor;
        std::unique_ptr<LogSentinel> logSentinel;
        const bsp::PowerProfile powerProfile;

        std::unique_ptr<sys::cpu::AlgorithmFactory> cpuAlgorithms;

M module-utils/log/CMakeLists.txt => module-utils/log/CMakeLists.txt +1 -0
@@ 20,6 20,7 @@ target_link_libraries(log
        utility
        purefs-paths
        crashdump-metadata-store
        Microsoft.GSL::GSL
    PUBLIC
        module-os
        log-api

M module-utils/log/Logger.cpp => module-utils/log/Logger.cpp +10 -0
@@ 7,6 7,7 @@
#include <purefs/filesystem_paths.hpp>
#include <fstream>
#include <CrashdumpMetadataStore.hpp>
#include <gsl/util>

namespace
{


@@ 187,6 188,15 @@ namespace Log
    /// @return:   1 - log flush successflul
    int Logger::dumpToFile(const std::filesystem::path &logDirectoryPath, LoggerState loggerState)
    {
        if (preDumpToFile != nullptr) {
            preDumpToFile();
        }
        auto _ = gsl::finally([this] {
            if (postDumpToFile != nullptr) {
                postDumpToFile();
            }
        });

        if (logFileName.empty()) {
            const auto &osMetadata = Store::CrashdumpMetadata::getInstance().getMetadataString();
            logFileName = std::string(logFileNamePrefix) + logFileNameSeparator + osMetadata + logFileNameExtension;

M module-utils/log/Logger.hpp => module-utils/log/Logger.hpp +5 -0
@@ 56,6 56,11 @@ namespace Log
        int flushLogs();
        [[nodiscard]] std::size_t getMaxLineLength();

        /// functions called immediately before and after dumping logs to a file
        /// created to synchronize necessary peripherals with the CPU frequency
        std::function<void()> preDumpToFile;
        std::function<void()> postDumpToFile;

        static constexpr auto CRIT_STR = "CRIT";
        static constexpr auto IRQ_STR  = "IRQ";


M pure_changelog.md => pure_changelog.md +1 -0
@@ 14,6 14,7 @@

* Fixed possible crash when entering phone number
* Fixed incorrect calculation of requested CPU frequency
* Fixed CPU frequency setting when dumping logs to a file

## [1.9.0 2023-10-19]