![support@xmrig.com](/assets/img/avatar_default.png)
17 changed files with 434 additions and 745 deletions
@ -0,0 +1,184 @@ |
|||
/* XMRig
|
|||
* Copyright (c) 2018-2019 tevador <tevador@gmail.com> |
|||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
|||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* 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, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
|
|||
#include "crypto/rx/RxMsr.h" |
|||
#include "backend/cpu/Cpu.h" |
|||
#include "backend/cpu/CpuThread.h" |
|||
#include "base/io/log/Log.h" |
|||
#include "base/tools/Chrono.h" |
|||
#include "crypto/rx/RxConfig.h" |
|||
#include "hw/msr/Msr.h" |
|||
|
|||
|
|||
#include <algorithm> |
|||
#include <set> |
|||
|
|||
|
|||
namespace xmrig { |
|||
|
|||
|
|||
bool RxMsr::m_enabled = false; |
|||
bool RxMsr::m_initialized = false; |
|||
|
|||
|
|||
static MsrItems items; |
|||
|
|||
|
|||
#ifdef XMRIG_OS_WIN |
|||
static constexpr inline int32_t get_cpu(int32_t) { return -1; } |
|||
#else |
|||
static constexpr inline int32_t get_cpu(int32_t cpu) { return cpu; } |
|||
#endif |
|||
|
|||
|
|||
static bool wrmsr(const MsrItems &preset, const std::vector<CpuThread> &threads, bool cache_qos, bool save) |
|||
{ |
|||
auto msr = Msr::get(); |
|||
if (!msr) { |
|||
return false; |
|||
} |
|||
|
|||
if (save) { |
|||
items.reserve(preset.size()); |
|||
|
|||
for (const auto &i : preset) { |
|||
auto item = msr->read(i.reg()); |
|||
if (!item.isValid()) { |
|||
items.clear(); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
LOG_VERBOSE("%s " CYAN_BOLD("0x%08" PRIx32) CYAN(":0x%016" PRIx64) CYAN_BOLD(" -> 0x%016" PRIx64), Msr::tag(), i.reg(), item.value(), MsrItem::maskedValue(item.value(), i.value(), i.mask())); |
|||
|
|||
items.emplace_back(item); |
|||
} |
|||
} |
|||
|
|||
// Which CPU cores will have access to the full L3 cache
|
|||
std::set<int32_t> cacheEnabled; |
|||
bool cacheQoSDisabled = threads.empty(); |
|||
|
|||
if (cache_qos) { |
|||
const auto &units = Cpu::info()->units(); |
|||
|
|||
for (const auto &t : threads) { |
|||
const auto affinity = static_cast<int32_t>(t.affinity()); |
|||
|
|||
// If some thread has no affinity or wrong affinity, disable cache QoS
|
|||
if (affinity < 0 || std::find(units.begin(), units.end(), affinity) == units.end()) { |
|||
cacheQoSDisabled = true; |
|||
|
|||
LOG_WARN("%s " YELLOW_BOLD("cache QoS can only be enabled when all mining threads have affinity set"), Msr::tag()); |
|||
break; |
|||
} |
|||
|
|||
cacheEnabled.insert(affinity); |
|||
} |
|||
} |
|||
|
|||
return msr->write([&msr, &preset, cache_qos, &cacheEnabled, cacheQoSDisabled](int32_t cpu) { |
|||
for (const auto &item : preset) { |
|||
if (!msr->write(item, get_cpu(cpu))) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
if (!cache_qos) { |
|||
return true; |
|||
} |
|||
|
|||
// Assign Class Of Service 0 to current CPU core (default, full L3 cache available)
|
|||
if (cacheQoSDisabled || cacheEnabled.count(cpu)) { |
|||
return msr->write(0xC8F, 0, get_cpu(cpu)); |
|||
} |
|||
|
|||
// Disable L3 cache for Class Of Service 1
|
|||
if (!msr->write(0xC91, 0, get_cpu(cpu))) { |
|||
// Some CPUs don't let set it to all zeros
|
|||
if (!msr->write(0xC91, 1, get_cpu(cpu))) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// Assign Class Of Service 1 to current CPU core
|
|||
return msr->write(0xC8F, 1ULL << 32, get_cpu(cpu)); |
|||
}); |
|||
} |
|||
|
|||
|
|||
} // namespace xmrig
|
|||
|
|||
|
|||
bool xmrig::RxMsr::init(const RxConfig &config, const std::vector<CpuThread> &threads) |
|||
{ |
|||
if (isInitialized()) { |
|||
return isEnabled(); |
|||
} |
|||
|
|||
m_initialized = true; |
|||
m_enabled = false; |
|||
|
|||
const auto &preset = config.msrPreset(); |
|||
if (preset.empty()) { |
|||
return false; |
|||
} |
|||
|
|||
const uint64_t ts = Chrono::steadyMSecs(); |
|||
bool cache_qos = config.cacheQoS(); |
|||
|
|||
if (cache_qos && !Cpu::info()->hasCatL3()) { |
|||
if (!threads.empty()) { |
|||
LOG_WARN("%s " YELLOW_BOLD("this CPU doesn't support cat_l3, cache QoS is unavailable"), Msr::tag()); |
|||
} |
|||
|
|||
cache_qos = false; |
|||
} |
|||
|
|||
if ((m_enabled = wrmsr(preset, threads, cache_qos, config.rdmsr()))) { |
|||
LOG_NOTICE("%s " GREEN_BOLD("register values for \"%s\" preset have been set successfully") BLACK_BOLD(" (%" PRIu64 " ms)"), Msr::tag(), config.msrPresetName(), Chrono::steadyMSecs() - ts); |
|||
} |
|||
else { |
|||
LOG_ERR("%s " RED_BOLD("FAILED TO APPLY MSR MOD, HASHRATE WILL BE LOW"), Msr::tag()); |
|||
} |
|||
|
|||
return isEnabled(); |
|||
} |
|||
|
|||
|
|||
void xmrig::RxMsr::destroy() |
|||
{ |
|||
if (!isInitialized()) { |
|||
return; |
|||
} |
|||
|
|||
m_initialized = false; |
|||
m_enabled = false; |
|||
|
|||
if (items.empty()) { |
|||
return; |
|||
} |
|||
|
|||
const uint64_t ts = Chrono::steadyMSecs(); |
|||
|
|||
if (!wrmsr(items, std::vector<CpuThread>(), true, false)) { |
|||
LOG_ERR("%s " RED_BOLD("failed to restore initial state" BLACK_BOLD(" (%" PRIu64 " ms)")), Msr::tag(), Chrono::steadyMSecs() - ts); |
|||
} |
|||
} |
@ -0,0 +1,53 @@ |
|||
/* XMRig
|
|||
* Copyright (c) 2018-2019 tevador <tevador@gmail.com> |
|||
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
|||
* Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* 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, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#ifndef XMRIG_RXMSR_H |
|||
#define XMRIG_RXMSR_H |
|||
|
|||
|
|||
#include <vector> |
|||
|
|||
|
|||
namespace xmrig |
|||
{ |
|||
|
|||
|
|||
class CpuThread; |
|||
class RxConfig; |
|||
|
|||
|
|||
class RxMsr |
|||
{ |
|||
public: |
|||
static inline bool isEnabled() { return m_enabled; } |
|||
static inline bool isInitialized() { return m_initialized; } |
|||
|
|||
static bool init(const RxConfig &config, const std::vector<CpuThread> &threads); |
|||
static void destroy(); |
|||
|
|||
private: |
|||
static bool m_enabled; |
|||
static bool m_initialized; |
|||
}; |
|||
|
|||
|
|||
} /* namespace xmrig */ |
|||
|
|||
|
|||
#endif /* XMRIG_RXMSR_H */ |
@ -1,272 +0,0 @@ |
|||
/* XMRig
|
|||
* Copyright (c) 2018-2019 tevador <tevador@gmail.com> |
|||
* Copyright (c) 2000 Transmeta Corporation <https://github.com/intel/msr-tools>
|
|||
* Copyright (c) 2004-2008 H. Peter Anvin <https://github.com/intel/msr-tools>
|
|||
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
|
|||
* Copyright (c) 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* 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, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
|
|||
#include "crypto/rx/Rx.h" |
|||
#include "backend/cpu/Cpu.h" |
|||
#include "backend/cpu/CpuThread.h" |
|||
#include "base/io/log/Log.h" |
|||
#include "base/tools/Chrono.h" |
|||
#include "crypto/rx/RxConfig.h" |
|||
|
|||
|
|||
#include <array> |
|||
#include <cctype> |
|||
#include <cinttypes> |
|||
#include <cstdio> |
|||
#include <dirent.h> |
|||
#include <fcntl.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/types.h> |
|||
#include <unistd.h> |
|||
|
|||
|
|||
namespace xmrig { |
|||
|
|||
|
|||
static const char *tag = YELLOW_BG_BOLD(WHITE_BOLD_S " msr ") " "; |
|||
static MsrItems savedState; |
|||
|
|||
|
|||
static inline int dir_filter(const struct dirent *dirp) |
|||
{ |
|||
return isdigit(dirp->d_name[0]) ? 1 : 0; |
|||
} |
|||
|
|||
|
|||
bool rdmsr_on_cpu(uint32_t reg, uint32_t cpu, uint64_t &value) |
|||
{ |
|||
char msr_file_name[64]{}; |
|||
|
|||
sprintf(msr_file_name, "/dev/cpu/%u/msr", cpu); |
|||
int fd = open(msr_file_name, O_RDONLY); |
|||
if (fd < 0) { |
|||
return false; |
|||
} |
|||
|
|||
const bool success = pread(fd, &value, sizeof value, reg) == sizeof value; |
|||
|
|||
close(fd); |
|||
|
|||
return success; |
|||
} |
|||
|
|||
|
|||
static MsrItem rdmsr(uint32_t reg) |
|||
{ |
|||
uint64_t value = 0; |
|||
if (!rdmsr_on_cpu(reg, 0, value)) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "cannot read MSR 0x%08" PRIx32, tag, reg); |
|||
|
|||
return {}; |
|||
} |
|||
|
|||
return { reg, value }; |
|||
} |
|||
|
|||
|
|||
static uint64_t get_masked_value(uint64_t old_value, uint64_t new_value, uint64_t mask) |
|||
{ |
|||
return (new_value & mask) | (old_value & ~mask); |
|||
} |
|||
|
|||
|
|||
static bool wrmsr_on_cpu(uint32_t reg, uint32_t cpu, uint64_t value, uint64_t mask) |
|||
{ |
|||
// If a bit in mask is set to 1, use new value, otherwise use old value
|
|||
if (mask != MsrItem::kNoMask) { |
|||
uint64_t old_value; |
|||
if (rdmsr_on_cpu(reg, cpu, old_value)) { |
|||
value = get_masked_value(old_value, value, mask); |
|||
} |
|||
} |
|||
|
|||
char msr_file_name[64]{}; |
|||
|
|||
sprintf(msr_file_name, "/dev/cpu/%u/msr", cpu); |
|||
int fd = open(msr_file_name, O_WRONLY); |
|||
if (fd < 0) { |
|||
return false; |
|||
} |
|||
|
|||
const bool success = pwrite(fd, &value, sizeof value, reg) == sizeof value; |
|||
|
|||
close(fd); |
|||
|
|||
return success; |
|||
} |
|||
|
|||
|
|||
template<typename T> |
|||
static bool wrmsr_on_all_cpus(uint32_t reg, uint64_t value, uint64_t mask, T&& callback) |
|||
{ |
|||
struct dirent **namelist; |
|||
int dir_entries = scandir("/dev/cpu", &namelist, dir_filter, 0); |
|||
int errors = 0; |
|||
|
|||
while (dir_entries--) { |
|||
if (!callback(reg, strtoul(namelist[dir_entries]->d_name, nullptr, 10), value, mask)) { |
|||
++errors; |
|||
} |
|||
|
|||
free(namelist[dir_entries]); |
|||
} |
|||
|
|||
free(namelist); |
|||
|
|||
if (errors) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "cannot set MSR 0x%08" PRIx32 " to 0x%08" PRIx64, tag, reg, value); |
|||
} |
|||
|
|||
return errors == 0; |
|||
} |
|||
|
|||
|
|||
static bool wrmsr_modprobe() |
|||
{ |
|||
if (system("/sbin/modprobe msr allow_writes=on > /dev/null 2>&1") != 0) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "msr kernel module is not available", tag); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
static bool wrmsr(const MsrItems& preset, const std::vector<CpuThread>& threads, bool cache_qos, bool save) |
|||
{ |
|||
if (!wrmsr_modprobe()) { |
|||
return false; |
|||
} |
|||
|
|||
if (save) { |
|||
for (const auto &i : preset) { |
|||
auto item = rdmsr(i.reg()); |
|||
LOG_VERBOSE(CLEAR "%s" CYAN_BOLD("0x%08" PRIx32) CYAN(":0x%016" PRIx64) CYAN_BOLD(" -> 0x%016" PRIx64), tag, i.reg(), item.value(), get_masked_value(item.value(), i.value(), i.mask())); |
|||
|
|||
if (item.isValid()) { |
|||
savedState.emplace_back(item); |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (const auto &i : preset) { |
|||
if (!wrmsr_on_all_cpus(i.reg(), i.value(), i.mask(), [](uint32_t reg, uint32_t cpu, uint64_t value, uint64_t mask) { return wrmsr_on_cpu(reg, cpu, value, mask); })) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
const uint32_t n = Cpu::info()->threads(); |
|||
|
|||
// Which CPU cores will have access to the full L3 cache
|
|||
std::vector<bool> cacheEnabled(n, false); |
|||
bool cacheQoSDisabled = threads.empty(); |
|||
|
|||
for (const CpuThread& t : threads) { |
|||
// If some thread has no affinity or wrong affinity, disable cache QoS
|
|||
if ((t.affinity() < 0) || (t.affinity() >= n)) { |
|||
cacheQoSDisabled = true; |
|||
if (cache_qos) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "Cache QoS can only be enabled when all mining threads have affinity set", tag); |
|||
} |
|||
break; |
|||
} |
|||
|
|||
cacheEnabled[t.affinity()] = true; |
|||
} |
|||
|
|||
if (cache_qos && !Cpu::info()->hasCatL3()) { |
|||
if (!threads.empty()) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "This CPU doesn't support cat_l3, cache QoS is unavailable", tag); |
|||
} |
|||
cache_qos = false; |
|||
} |
|||
|
|||
bool result = true; |
|||
|
|||
if (cache_qos) { |
|||
result = wrmsr_on_all_cpus(0xC8F, 0, MsrItem::kNoMask, [&cacheEnabled, cacheQoSDisabled](uint32_t, uint32_t cpu, uint64_t, uint64_t) { |
|||
if (cacheQoSDisabled || (cpu >= cacheEnabled.size()) || cacheEnabled[cpu]) { |
|||
// Assign Class Of Service 0 to current CPU core (default, full L3 cache available)
|
|||
if (!wrmsr_on_cpu(0xC8F, cpu, 0, MsrItem::kNoMask)) { |
|||
return false; |
|||
} |
|||
} |
|||
else { |
|||
// Disable L3 cache for Class Of Service 1
|
|||
if (!wrmsr_on_cpu(0xC91, cpu, 0, MsrItem::kNoMask)) { |
|||
// Some CPUs don't let set it to all zeros
|
|||
if (!wrmsr_on_cpu(0xC91, cpu, 1, MsrItem::kNoMask)) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
// Assign Class Of Service 1 to current CPU core
|
|||
if (!wrmsr_on_cpu(0xC8F, cpu, 1ULL << 32, MsrItem::kNoMask)) { |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
}); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
|
|||
} // namespace xmrig
|
|||
|
|||
|
|||
bool xmrig::Rx::msrInit(const RxConfig &config, const std::vector<CpuThread> &threads) |
|||
{ |
|||
const auto &preset = config.msrPreset(); |
|||
if (preset.empty()) { |
|||
return false; |
|||
} |
|||
|
|||
const uint64_t ts = Chrono::steadyMSecs(); |
|||
|
|||
if (wrmsr(preset, threads, config.cacheQoS(), config.rdmsr())) { |
|||
LOG_NOTICE(CLEAR "%s" GREEN_BOLD_S "register values for \"%s\" preset have been set successfully" BLACK_BOLD(" (%" PRIu64 " ms)"), tag, config.msrPresetName(), Chrono::steadyMSecs() - ts); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
LOG_ERR(CLEAR "%s" RED_BOLD_S "FAILED TO APPLY MSR MOD, HASHRATE WILL BE LOW", tag); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
void xmrig::Rx::msrDestroy() |
|||
{ |
|||
if (savedState.empty()) { |
|||
return; |
|||
} |
|||
|
|||
const uint64_t ts = Chrono::steadyMSecs(); |
|||
|
|||
if (!wrmsr(savedState, std::vector<CpuThread>(), true, false)) { |
|||
LOG_ERR(CLEAR "%s" RED_BOLD_S "failed to restore initial state" BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts); |
|||
} |
|||
} |
@ -1,386 +0,0 @@ |
|||
/* XMRig
|
|||
* Copyright (c) 2018-2019 tevador <tevador@gmail.com> |
|||
* Copyright (c) 2000 Transmeta Corporation <https://github.com/intel/msr-tools>
|
|||
* Copyright (c) 2004-2008 H. Peter Anvin <https://github.com/intel/msr-tools>
|
|||
* Copyright (c) 2007-2009 hiyohiyo <https://openlibsys.org>, <hiyohiyo@crystalmark.info>
|
|||
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
|
|||
* Copyright (c) 2016-2020 XMRig <https://github.com/xmrig>, <support@xmrig.com>
|
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* 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, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
|
|||
#include "crypto/rx/Rx.h" |
|||
#include "backend/cpu/Cpu.h" |
|||
#include "backend/cpu/CpuThread.h" |
|||
#include "base/io/log/Log.h" |
|||
#include "base/kernel/Platform.h" |
|||
#include "base/tools/Chrono.h" |
|||
#include "crypto/rx/RxConfig.h" |
|||
|
|||
|
|||
#include <windows.h> |
|||
#include <array> |
|||
#include <string> |
|||
#include <thread> |
|||
|
|||
|
|||
#define SERVICE_NAME L"WinRing0_1_2_0" |
|||
|
|||
|
|||
namespace xmrig { |
|||
|
|||
|
|||
static bool reuseDriver = false; |
|||
static const char *tag = YELLOW_BG_BOLD(WHITE_BOLD_S " msr ") " "; |
|||
static MsrItems savedState; |
|||
|
|||
|
|||
static SC_HANDLE hManager; |
|||
static SC_HANDLE hService; |
|||
|
|||
|
|||
static bool wrmsr_uninstall_driver() |
|||
{ |
|||
if (!hService) { |
|||
return true; |
|||
} |
|||
|
|||
bool result = true; |
|||
|
|||
if (!reuseDriver) { |
|||
SERVICE_STATUS serviceStatus; |
|||
|
|||
if (!ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus)) { |
|||
result = false; |
|||
} |
|||
|
|||
if (!DeleteService(hService)) { |
|||
LOG_ERR(CLEAR "%s" RED_S "failed to remove WinRing0 driver, error %u", tag, GetLastError()); |
|||
result = false; |
|||
} |
|||
} |
|||
|
|||
CloseServiceHandle(hService); |
|||
hService = nullptr; |
|||
|
|||
return result; |
|||
} |
|||
|
|||
|
|||
static HANDLE wrmsr_install_driver() |
|||
{ |
|||
DWORD err = 0; |
|||
|
|||
hManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_ALL_ACCESS); |
|||
if (!hManager) { |
|||
err = GetLastError(); |
|||
|
|||
if (err == ERROR_ACCESS_DENIED) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "to write MSR registers Administrator privileges required.", tag); |
|||
} |
|||
else { |
|||
LOG_ERR(CLEAR "%s" RED_S "failed to open service control manager, error %u", tag, err); |
|||
} |
|||
|
|||
return nullptr; |
|||
} |
|||
|
|||
std::vector<wchar_t> dir; |
|||
dir.resize(MAX_PATH); |
|||
do { |
|||
dir.resize(dir.size() * 2); |
|||
GetModuleFileNameW(nullptr, dir.data(), dir.size()); |
|||
err = GetLastError(); |
|||
} while (err == ERROR_INSUFFICIENT_BUFFER); |
|||
|
|||
if (err != ERROR_SUCCESS) { |
|||
LOG_ERR(CLEAR "%s" RED_S "failed to get path to driver, error %u", tag, err); |
|||
return nullptr; |
|||
} |
|||
|
|||
for (auto it = dir.end() - 1; it != dir.begin(); --it) { |
|||
if ((*it == L'\\') || (*it == L'/')) { |
|||
++it; |
|||
*it = L'\0'; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
std::wstring driverPath = dir.data(); |
|||
driverPath += L"WinRing0x64.sys"; |
|||
|
|||
hService = OpenServiceW(hManager, SERVICE_NAME, SERVICE_ALL_ACCESS); |
|||
if (hService) { |
|||
LOG_WARN(CLEAR "%s" YELLOW("service ") YELLOW_BOLD("WinRing0_1_2_0") YELLOW(" already exists"), tag); |
|||
|
|||
SERVICE_STATUS status; |
|||
const auto rc = QueryServiceStatus(hService, &status); |
|||
|
|||
if (rc) { |
|||
DWORD dwBytesNeeded; |
|||
|
|||
QueryServiceConfigA(hService, nullptr, 0, &dwBytesNeeded); |
|||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { |
|||
std::vector<BYTE> buffer(dwBytesNeeded); |
|||
auto config = reinterpret_cast<LPQUERY_SERVICE_CONFIGA>(buffer.data()); |
|||
|
|||
if (QueryServiceConfigA(hService, config, buffer.size(), &dwBytesNeeded)) { |
|||
LOG_INFO(CLEAR "%s" YELLOW("service path: ") YELLOW_BOLD("\"%s\""), tag, config->lpBinaryPathName); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (rc && status.dwCurrentState == SERVICE_RUNNING) { |
|||
reuseDriver = true; |
|||
} |
|||
else if (!wrmsr_uninstall_driver()) { |
|||
return nullptr; |
|||
} |
|||
} |
|||
|
|||
if (!reuseDriver) { |
|||
hService = CreateServiceW(hManager, SERVICE_NAME, SERVICE_NAME, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, driverPath.c_str(), nullptr, nullptr, nullptr, nullptr, nullptr); |
|||
if (!hService) { |
|||
LOG_ERR(CLEAR "%s" RED_S "failed to install WinRing0 driver, error %u", tag, GetLastError()); |
|||
|
|||
return nullptr; |
|||
} |
|||
|
|||
if (!StartService(hService, 0, nullptr)) { |
|||
err = GetLastError(); |
|||
if (err != ERROR_SERVICE_ALREADY_RUNNING) { |
|||
if (err == ERROR_FILE_NOT_FOUND) { |
|||
LOG_ERR(CLEAR "%s" RED("failed to start WinRing0 driver: ") RED_BOLD("\"WinRing0x64.sys not found\""), tag); |
|||
} |
|||
else { |
|||
LOG_ERR(CLEAR "%s" RED_S "failed to start WinRing0 driver, error %u", tag, err); |
|||
} |
|||
|
|||
wrmsr_uninstall_driver(); |
|||
|
|||
return nullptr; |
|||
} |
|||
} |
|||
} |
|||
|
|||
HANDLE hDriver = CreateFileW(L"\\\\.\\" SERVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); |
|||
if (!hDriver) { |
|||
LOG_ERR(CLEAR "%s" RED_S "failed to connect to WinRing0 driver, error %u", tag, GetLastError()); |
|||
|
|||
return nullptr; |
|||
} |
|||
|
|||
return hDriver; |
|||
} |
|||
|
|||
|
|||
#define IOCTL_READ_MSR CTL_CODE(40000, 0x821, METHOD_BUFFERED, FILE_ANY_ACCESS) |
|||
#define IOCTL_WRITE_MSR CTL_CODE(40000, 0x822, METHOD_BUFFERED, FILE_ANY_ACCESS) |
|||
|
|||
|
|||
static bool rdmsr(HANDLE driver, uint32_t reg, uint64_t &value) |
|||
{ |
|||
DWORD size = 0; |
|||
|
|||
return DeviceIoControl(driver, IOCTL_READ_MSR, ®, sizeof(reg), &value, sizeof(value), &size, nullptr) != 0; |
|||
} |
|||
|
|||
|
|||
static MsrItem rdmsr(HANDLE driver, uint32_t reg) |
|||
{ |
|||
uint64_t value = 0; |
|||
if (!rdmsr(driver, reg, value)) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "cannot read MSR 0x%08" PRIx32, tag, reg); |
|||
|
|||
return {}; |
|||
} |
|||
|
|||
return { reg, value }; |
|||
} |
|||
|
|||
|
|||
static uint64_t get_masked_value(uint64_t old_value, uint64_t new_value, uint64_t mask) |
|||
{ |
|||
return (new_value & mask) | (old_value & ~mask); |
|||
} |
|||
|
|||
|
|||
static bool wrmsr(HANDLE driver, uint32_t reg, uint64_t value, uint64_t mask) |
|||
{ |
|||
struct { |
|||
uint32_t reg = 0; |
|||
uint32_t value[2]{}; |
|||
} input; |
|||
|
|||
static_assert(sizeof(input) == 12, "Invalid struct size for WinRing0 driver"); |
|||
|
|||
// If a bit in mask is set to 1, use new value, otherwise use old value
|
|||
if (mask != MsrItem::kNoMask) { |
|||
uint64_t old_value; |
|||
if (rdmsr(driver, reg, old_value)) { |
|||
value = get_masked_value(old_value, value, mask); |
|||
} |
|||
} |
|||
|
|||
input.reg = reg; |
|||
*(reinterpret_cast<uint64_t*>(input.value)) = value; |
|||
|
|||
DWORD output; |
|||
DWORD k; |
|||
|
|||
if (!DeviceIoControl(driver, IOCTL_WRITE_MSR, &input, sizeof(input), &output, sizeof(output), &k, nullptr)) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "cannot set MSR 0x%08" PRIx32 " to 0x%08" PRIx64, tag, reg, value); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
static bool wrmsr(const MsrItems &preset, const std::vector<CpuThread>& threads, bool cache_qos, bool save) |
|||
{ |
|||
bool success = true; |
|||
|
|||
HANDLE driver = wrmsr_install_driver(); |
|||
if (!driver) { |
|||
wrmsr_uninstall_driver(); |
|||
|
|||
if (hManager) { |
|||
CloseServiceHandle(hManager); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
if (save) { |
|||
for (const auto &i : preset) { |
|||
auto item = rdmsr(driver, i.reg()); |
|||
LOG_VERBOSE(CLEAR "%s" CYAN_BOLD("0x%08" PRIx32) CYAN(":0x%016" PRIx64) CYAN_BOLD(" -> 0x%016" PRIx64), tag, i.reg(), item.value(), get_masked_value(item.value(), i.value(), i.mask())); |
|||
|
|||
if (item.isValid()) { |
|||
savedState.emplace_back(item); |
|||
} |
|||
} |
|||
} |
|||
|
|||
const uint32_t n = Cpu::info()->threads(); |
|||
|
|||
// Which CPU cores will have access to the full L3 cache
|
|||
std::vector<bool> cacheEnabled(n, false); |
|||
bool cacheQoSDisabled = threads.empty(); |
|||
|
|||
for (const CpuThread& t : threads) { |
|||
// If some thread has no affinity or wrong affinity, disable cache QoS
|
|||
if ((t.affinity() < 0) || (t.affinity() >= n)) { |
|||
cacheQoSDisabled = true; |
|||
if (cache_qos) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "Cache QoS can only be enabled when all mining threads have affinity set", tag); |
|||
} |
|||
break; |
|||
} |
|||
|
|||
cacheEnabled[t.affinity()] = true; |
|||
} |
|||
|
|||
if (cache_qos && !Cpu::info()->hasCatL3()) { |
|||
if (!threads.empty()) { |
|||
LOG_WARN(CLEAR "%s" YELLOW_BOLD_S "This CPU doesn't support cat_l3, cache QoS is unavailable", tag); |
|||
} |
|||
cache_qos = false; |
|||
} |
|||
|
|||
std::thread wrmsr_thread([n, driver, &preset, &cacheEnabled, cache_qos, cacheQoSDisabled, &success]() { |
|||
for (uint32_t i = 0; i < n; ++i) { |
|||
if (!Platform::setThreadAffinity(i)) { |
|||
continue; |
|||
} |
|||
|
|||
for (const auto &i : preset) { |
|||
success &= wrmsr(driver, i.reg(), i.value(), i.mask()); |
|||
} |
|||
|
|||
if (cache_qos) { |
|||
if (cacheQoSDisabled || cacheEnabled[i]) { |
|||
// Assign Class Of Service 0 to current CPU core (default, full L3 cache available)
|
|||
success &= wrmsr(driver, 0xC8F, 0, MsrItem::kNoMask); |
|||
} |
|||
else { |
|||
// Disable L3 cache for Class Of Service 1
|
|||
if (!wrmsr(driver, 0xC91, 0, MsrItem::kNoMask)) { |
|||
// Some CPUs don't let set it to all zeros
|
|||
if (!wrmsr(driver, 0xC91, 1, MsrItem::kNoMask)) { |
|||
success = false; |
|||
} |
|||
} |
|||
|
|||
// Assign Class Of Service 1 to current CPU core
|
|||
success &= wrmsr(driver, 0xC8F, 1ULL << 32, MsrItem::kNoMask); |
|||
} |
|||
} |
|||
|
|||
if (!success) { |
|||
break; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
wrmsr_thread.join(); |
|||
|
|||
CloseHandle(driver); |
|||
|
|||
wrmsr_uninstall_driver(); |
|||
CloseServiceHandle(hManager); |
|||
|
|||
return success; |
|||
} |
|||
|
|||
|
|||
} // namespace xmrig
|
|||
|
|||
|
|||
bool xmrig::Rx::msrInit(const RxConfig &config, const std::vector<CpuThread>& threads) |
|||
{ |
|||
const auto &preset = config.msrPreset(); |
|||
if (preset.empty()) { |
|||
return false; |
|||
} |
|||
|
|||
const uint64_t ts = Chrono::steadyMSecs(); |
|||
|
|||
if (wrmsr(preset, threads, config.cacheQoS(), config.rdmsr())) { |
|||
LOG_NOTICE(CLEAR "%s" GREEN_BOLD_S "register values for \"%s\" preset has been set successfully" BLACK_BOLD(" (%" PRIu64 " ms)"), tag, config.msrPresetName(), Chrono::steadyMSecs() - ts); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
LOG_ERR(CLEAR "%s" RED_BOLD_S "FAILED TO APPLY MSR MOD, HASHRATE WILL BE LOW", tag); |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
void xmrig::Rx::msrDestroy() |
|||
{ |
|||
if (savedState.empty()) { |
|||
return; |
|||
} |
|||
|
|||
const uint64_t ts = Chrono::steadyMSecs(); |
|||
|
|||
if (!wrmsr(savedState, std::vector<CpuThread>(), true, false)) { |
|||
LOG_ERR(CLEAR "%s" RED_BOLD_S "failed to restore initial state" BLACK_BOLD(" (%" PRIu64 " ms)"), tag, Chrono::steadyMSecs() - ts); |
|||
} |
|||
} |
Loading…
Reference in new issue