Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ LOCAL_SRC_FILES := \
src/thd_gddv.cpp \
src/thd_platform.cpp \
src/thd_platform_intel.cpp \
src/thd_platform_arm.cpp
src/thd_platform_arm.cpp \
src/thd_util.cpp \
src/thd_cdev_rapl_restore.cpp \
src/thd_features_parse.cpp

LOCAL_C_INCLUDES += external/libxml2/include

Expand Down
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ thermald_SOURCES = \
src/thd_zone_generic.cpp \
src/thd_cdev_cpufreq.cpp \
src/thd_cdev_rapl.cpp \
src/thd_cdev_rapl_restore.cpp \
src/thd_cdev_intel_pstate_driver.cpp \
src/thd_rapl_power_meter.cpp \
src/thd_trt_art_reader.cpp \
Expand Down
28 changes: 28 additions & 0 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,34 @@ For build, follow the same procedure as Fedora.

Releases

Release 2.5.12-rc1
- Platform and feature expansion: added ARM backend support, Intel platform refactoring,
new CPU IDs including NovaLake variants, generic_os/data-vault path enhancements,
and feature enable/disable via config.

- Maintainability and tooling: significant modernization/cleanup (mutex to C++11,
nullptr/constexpr, safer string helpers, clang-tidy/coverity fixes), plus CI and
test/script cleanup and removal of deprecated dptfxtract references.

- Data-vault and parser improvements: optimized config/data-vault read paths, sanitized
firmware-sourced vault data, added structural checks for malformed tables, and
improved parser reliability.

- Adaptive/power control updates: adaptive-mode behavior was tightened
(fail/exit paths, ignore-default-control handling), platform gating was improved
(adaptive-only for select new CPUs), and RAPL handling improved with register
store/restore on exit plus safer power-limit logic.

- Security hardening: tightened D-Bus input validation and error handling,
sanitized zone names/paths, restricted writes to sys, expanded O_NOFOLLOW usage,
removed mem MMIO workaround, and added stronger XML/config file validation
through a shared open_validated_xml_file() path.

- Memory-safety and robustness: added broad range/bounds checks (sysfs, cpufreq, XML,
APCT/IDSP/data vault), max limits for zones/cooling devices/segments/conditions,
fixed lock/unlock and stale mutex issues, guarded container operations, and
improved exception safety (e.g., unique_ptr use for virtual sensor links).

Release 2.5.11
- Clang-tidy fixes
- Wildcat Lake support
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
AC_PREREQ(1.0)

m4_define([td_major_version], [2])
m4_define([td_minor_version], [5.11])
m4_define([td_minor_version], [5.12-rc1])
m4_define([td_version],
[td_major_version.td_minor_version])

Expand Down
1 change: 1 addition & 0 deletions src/android_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ bool workaround_enabled = false;
bool disable_active_power = false;
bool ignore_critical = false;
bool power_floor_enable = false;
bool adaptive_perf_enable = false;

static int pid_file_handle;

Expand Down
3 changes: 3 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ bool workaround_enabled = false;
bool disable_active_power = false;
bool ignore_critical = false;
bool power_floor_enable = false;
bool adaptive_perf_enable = false;

// check cpuid
static gboolean ignore_cpuid_check = false;
Expand Down Expand Up @@ -353,8 +354,10 @@ int main(int argc, char *argv[]) {
}

if (adaptive) {
adaptive_perf_enable = true;
ret = thd_engine_create_adaptive_engine((bool) ignore_cpuid_check, (bool) test_mode);
if (ret != THD_SUCCESS) {
adaptive_perf_enable = false;
thd_log_info("--adaptive option failed on this platform\n");
Comment on lines 356 to 361
thd_log_info("Ignoring --adaptive option\n");
ret = thd_engine_create_default_engine((bool) ignore_cpuid_check,
Expand Down
18 changes: 14 additions & 4 deletions src/thd_cdev_order_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,33 @@
#include "thd_sys_fs.h"
#include "thd_util.h"

static constexpr int thd_xml_parse_options = XML_PARSE_NONET | XML_PARSE_NOERROR
| XML_PARSE_NOWARNING;

cthd_cdev_order_parse::cthd_cdev_order_parse() :
doc(nullptr), root_element(nullptr) {
std::string name = TDCONFDIR;
filename = name + "/" "thermal-cpu-cdev-order.xml";
}

int cthd_cdev_order_parse::parser_init() {
struct stat s;

if (stat(filename.c_str(), &s))
int fd = open_validated_xml_file(filename);
if (fd < 0)
return THD_ERROR;

doc = xmlReadFile(filename.c_str(), nullptr, 0);
doc = xmlReadFd(fd, filename.c_str(), nullptr, thd_xml_parse_options);
close(fd);
if (doc == nullptr) {
thd_log_msg("error: could not parse file %s\n", filename.c_str());
return THD_ERROR;
}

if (doc->intSubset != nullptr || doc->extSubset != nullptr) {
thd_log_warn("Config file %s must not contain a DTD\n", filename.c_str());
xmlFreeDoc(doc);
doc = nullptr;
return THD_ERROR;
}
root_element = xmlDocGetRootElement(doc);

if (root_element == nullptr) {
Expand Down
2 changes: 2 additions & 0 deletions src/thd_cdev_rapl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,8 @@ int cthd_sysfs_cdev_rapl::update() {
if (rapl_sysfs_valid())
return THD_ERROR;

register_for_restoration();

Comment on lines 379 to +383
ppcc = read_ppcc_power_limits();

if (ppcc) {
Expand Down
1 change: 1 addition & 0 deletions src/thd_cdev_rapl.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class cthd_sysfs_cdev_rapl: public cthd_cdev {
int rapl_update_time_window(int time_window);
int rapl_update_pl2_time_window(int time_window);
int rapl_read_enable_status();
void register_for_restoration();

public:
static constexpr int rapl_no_time_windows = 6;
Expand Down
130 changes: 130 additions & 0 deletions src/thd_cdev_rapl_restore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* cthd_cdev_rapl_restore.cpp: RAPL power limit restoration on exit
* using RAPL
Comment on lines +1 to +3
* Copyright (C) 2026 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 or later as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name <Srinivas.Pandruvada@linux.intel.com>
*
*/

#include "thd_cdev_rapl.h"
#include "thermald.h"
#include <vector>
#include <mutex>
#include <cstdlib>

// Global registry of RAPL devices that need restoration on exit
namespace {
struct rapl_restore_info {
std::string sysfs_path;
int constraint_index;
int power_limit;
int time_window;
int enable_status;
};

std::vector<rapl_restore_info> restore_registry;
std::mutex registry_mutex;
bool atexit_registered = false;

// Called by atexit() - restores all RAPL power limits
void restore_rapl_limits() {
std::vector<rapl_restore_info> registry_copy;
{
std::lock_guard<std::mutex> lock(registry_mutex);
registry_copy = restore_registry;
}

thd_log_info("Restoring %zu RAPL power limits on exit\n",
registry_copy.size());

for (const auto& info : registry_copy) {
csys_fs sysfs(info.sysfs_path);
Comment on lines +46 to +57

// Restore PL1 power limit
std::ostringstream power_limit_path;
power_limit_path << "constraint_" << info.constraint_index << "_power_limit_uw";
if (sysfs.exists(power_limit_path.str())) {
sysfs.write(power_limit_path.str(), info.power_limit);
thd_log_info(" Restored PL1=%d uW for %s\n",
info.power_limit, info.sysfs_path.c_str());
}

// Restore time window
std::ostringstream time_window_path;
time_window_path << "constraint_" << info.constraint_index << "_time_window_us";
if (sysfs.exists(time_window_path.str())) {
sysfs.write(time_window_path.str(), info.time_window);
thd_log_info(" Restored PL1 time window=%d for %s\n",
info.time_window, info.sysfs_path.c_str());
}

// Restore enable status
if (sysfs.exists("enabled")) {
sysfs.write("enabled", info.enable_status);
thd_log_info(" Restored PL1 enabled=%d for %s\n",
info.enable_status, info.sysfs_path.c_str());
}
}
}
}

// Register a RAPL device for restoration on exit
void cthd_sysfs_cdev_rapl::register_for_restoration() {
std::lock_guard<std::mutex> lock(registry_mutex);

// Register atexit handler on first call
if (!atexit_registered) {
if (std::atexit(restore_rapl_limits) != 0) {
thd_log_warn("Failed to register RAPL power limit restoration handler\n");
return;
}
atexit_registered = true;
thd_log_info("Registered RAPL power limit restoration handler\n");
}

const std::string sysfs_path = cdev_sysfs.get_base_path();
for (const auto &existing : restore_registry) {
if (existing.sysfs_path == sysfs_path
&& existing.constraint_index == constraint_index) {
return;
}
}

const int power_limit = rapl_read_pl1();
const int time_window = rapl_read_time_window();
const int enable_status = rapl_read_enable_status();
if (power_limit < 0 || time_window < 0 || enable_status < 0) {
thd_log_warn(
"Failed to read initial RAPL state for %s, skipping restoration registration\n",
sysfs_path.c_str());
return;
}

rapl_restore_info info;
info.sysfs_path = sysfs_path;
info.constraint_index = constraint_index;
info.power_limit = power_limit;
info.time_window = time_window;
info.enable_status = enable_status;

restore_registry.push_back(info);

thd_log_info("Registered RAPL %s: PL1=%d uW, window=%d us, enable=%d\n",
sysfs_path.c_str(), info.power_limit, info.time_window, info.enable_status);
}
Comment on lines +88 to +130
12 changes: 12 additions & 0 deletions src/thd_dbus_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "thd_sensor.h"
#include "thd_zone.h"
#include "thd_trip_point.h"
#include "thd_util.h"

#include <gio/gio.h>
#include <glib.h>
Expand Down Expand Up @@ -232,6 +233,8 @@ gboolean thd_dbus_interface_reinit(PrefObject *obj, GError **error) {

gboolean thd_dbus_interface_set_user_max_temperature(PrefObject *obj,
gchar *zone_name, unsigned int temperature, GError **error) {
if (zone_name == nullptr || !is_valid_thermal_object_name(zone_name))
return FALSE;

thd_log_debug("thd_dbus_interface_set_user_set_point %s:%d\n", zone_name,
temperature);
Expand All @@ -250,6 +253,8 @@ gboolean thd_dbus_interface_set_user_max_temperature(PrefObject *obj,

gboolean thd_dbus_interface_set_user_passive_temperature(PrefObject *obj,
gchar *zone_name, unsigned int temperature, GError **error) {
if (zone_name == nullptr || !is_valid_thermal_object_name(zone_name))
return FALSE;

thd_log_debug("thd_dbus_interface_set_user_passive_temperature %s:%u\n",
zone_name, temperature);
Expand Down Expand Up @@ -288,6 +293,11 @@ gboolean thd_dbus_interface_add_virtual_sensor(PrefObject *obj, gchar *name,
int ret;

g_assert(obj != nullptr);
if (name == nullptr || !is_valid_thermal_object_name(name))
return FALSE;
if (!is_valid_finite_value(slope, -1000.0, 1000.0)
|| !is_valid_finite_value(intercept, -1000.0, 1000.0))
return FALSE;
Comment on lines 295 to +300

thd_log_debug("thd_dbus_interface_add_sensor %s:%s\n", (char*) name,
(char *) dep_sensor);
Expand Down Expand Up @@ -479,6 +489,8 @@ gboolean thd_dbus_interface_add_zone_passive(PrefObject *obj, gchar *zone_name,
int ret;

g_assert(obj != nullptr);
if (zone_name == nullptr || !is_valid_thermal_object_name(zone_name))
return FALSE;

thd_log_debug("thd_dbus_interface_add_zone_passive %s\n",
(char*) zone_name);
Expand Down
Loading
Loading