mirror of
https://github.com/xmrig/xmrig.git
synced 2024-12-23 03:59:41 +00:00
Added RxMsr class.
This commit is contained in:
parent
b9d813c403
commit
9dae559b73
17 changed files with 435 additions and 746 deletions
|
@ -101,25 +101,25 @@ if (WITH_RANDOMX)
|
||||||
|
|
||||||
if (XMRIG_OS_WIN)
|
if (XMRIG_OS_WIN)
|
||||||
list(APPEND SOURCES_CRYPTO
|
list(APPEND SOURCES_CRYPTO
|
||||||
src/crypto/rx/Rx_win.cpp
|
|
||||||
src/hw/msr/Msr_win.cpp
|
|
||||||
src/crypto/rx/RxFix_win.cpp
|
src/crypto/rx/RxFix_win.cpp
|
||||||
|
src/hw/msr/Msr_win.cpp
|
||||||
)
|
)
|
||||||
elseif (XMRIG_OS_LINUX)
|
elseif (XMRIG_OS_LINUX)
|
||||||
list(APPEND SOURCES_CRYPTO
|
list(APPEND SOURCES_CRYPTO
|
||||||
src/crypto/rx/Rx_linux.cpp
|
|
||||||
src/hw/msr/Msr_linux.cpp
|
|
||||||
src/crypto/rx/RxFix_linux.cpp
|
src/crypto/rx/RxFix_linux.cpp
|
||||||
|
src/hw/msr/Msr_linux.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND HEADERS_CRYPTO
|
list(APPEND HEADERS_CRYPTO
|
||||||
src/crypto/rx/RxFix.h
|
src/crypto/rx/RxFix.h
|
||||||
|
src/crypto/rx/RxMsr.h
|
||||||
src/hw/msr/Msr.h
|
src/hw/msr/Msr.h
|
||||||
src/hw/msr/MsrItem.h
|
src/hw/msr/MsrItem.h
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND SOURCES_CRYPTO
|
list(APPEND SOURCES_CRYPTO
|
||||||
|
src/crypto/rx/RxMsr.cpp
|
||||||
src/hw/msr/Msr.cpp
|
src/hw/msr/Msr.cpp
|
||||||
src/hw/msr/MsrItem.cpp
|
src/hw/msr/MsrItem.cpp
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* XMRig
|
/* XMRig
|
||||||
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
|
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||||
* Copyright (c) 2016-2020 XMRig <support@xmrig.com>
|
* Copyright (c) 2016-2021 XMRig <support@xmrig.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -86,18 +86,21 @@ public:
|
||||||
inline constexpr static bool is64bit() { return false; }
|
inline constexpr static bool is64bit() { return false; }
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
virtual Arch arch() const = 0;
|
||||||
virtual Assembly::Id assembly() const = 0;
|
virtual Assembly::Id assembly() const = 0;
|
||||||
virtual bool has(Flag feature) const = 0;
|
virtual bool has(Flag feature) const = 0;
|
||||||
virtual bool hasAES() const = 0;
|
virtual bool hasAES() const = 0;
|
||||||
virtual bool hasAVX() const = 0;
|
virtual bool hasAVX() const = 0;
|
||||||
virtual bool hasAVX2() const = 0;
|
virtual bool hasAVX2() const = 0;
|
||||||
virtual bool hasBMI2() const = 0;
|
virtual bool hasBMI2() const = 0;
|
||||||
|
virtual bool hasCatL3() const = 0;
|
||||||
virtual bool hasOneGbPages() const = 0;
|
virtual bool hasOneGbPages() const = 0;
|
||||||
virtual bool hasXOP() const = 0;
|
virtual bool hasXOP() const = 0;
|
||||||
virtual bool hasCatL3() const = 0;
|
|
||||||
virtual bool isVM() const = 0;
|
virtual bool isVM() const = 0;
|
||||||
|
virtual bool jccErratum() const = 0;
|
||||||
virtual const char *backend() const = 0;
|
virtual const char *backend() const = 0;
|
||||||
virtual const char *brand() const = 0;
|
virtual const char *brand() const = 0;
|
||||||
|
virtual const std::vector<int32_t> &units() const = 0;
|
||||||
virtual CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const = 0;
|
virtual CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const = 0;
|
||||||
virtual MsrMod msrMod() const = 0;
|
virtual MsrMod msrMod() const = 0;
|
||||||
virtual rapidjson::Value toJSON(rapidjson::Document &doc) const = 0;
|
virtual rapidjson::Value toJSON(rapidjson::Document &doc) const = 0;
|
||||||
|
@ -108,8 +111,6 @@ public:
|
||||||
virtual size_t packages() const = 0;
|
virtual size_t packages() const = 0;
|
||||||
virtual size_t threads() const = 0;
|
virtual size_t threads() const = 0;
|
||||||
virtual Vendor vendor() const = 0;
|
virtual Vendor vendor() const = 0;
|
||||||
virtual Arch arch() const = 0;
|
|
||||||
virtual bool jccErratum() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* XMRig
|
/* XMRig
|
||||||
* Copyright (c) 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
* Copyright (c) 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||||
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
|
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||||
* Copyright (c) 2016-2020 XMRig <support@xmrig.com>
|
* Copyright (c) 2016-2021 XMRig <support@xmrig.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -190,6 +190,11 @@ xmrig::BasicCpuInfo::BasicCpuInfo() :
|
||||||
m_flags.set(FLAG_CAT_L3, has_cat_l3());
|
m_flags.set(FLAG_CAT_L3, has_cat_l3());
|
||||||
m_flags.set(FLAG_VM, is_vm());
|
m_flags.set(FLAG_VM, is_vm());
|
||||||
|
|
||||||
|
m_units.resize(m_threads);
|
||||||
|
for (int32_t i = 0; i < static_cast<int32_t>(m_threads); ++i) {
|
||||||
|
m_units[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
# ifdef XMRIG_FEATURE_ASM
|
# ifdef XMRIG_FEATURE_ASM
|
||||||
if (hasAES()) {
|
if (hasAES()) {
|
||||||
char vendor[13] = { 0 };
|
char vendor[13] = { 0 };
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
/* XMRig
|
/* XMRig
|
||||||
* Copyright 2010 Jeff Garzik <jgarzik@pobox.com>
|
* Copyright (c) 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
||||||
* Copyright 2012-2014 pooler <pooler@litecoinpool.org>
|
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||||
* Copyright 2014 Lucas Jones <https://github.com/lucasjones>
|
* Copyright (c) 2016-2021 XMRig <support@xmrig.com>
|
||||||
* Copyright 2014-2016 Wolf9466 <https://github.com/OhGodAPet>
|
|
||||||
* Copyright 2016 Jay D Dee <jayddee246@gmail.com>
|
|
||||||
* Copyright 2017-2019 XMR-Stak <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
|
|
||||||
* Copyright 2018-2020 SChernykh <https://github.com/SChernykh>
|
|
||||||
* Copyright 2016-2020 XMRig <support@xmrig.com>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -45,17 +40,20 @@ protected:
|
||||||
CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
|
CpuThreads threads(const Algorithm &algorithm, uint32_t limit) const override;
|
||||||
rapidjson::Value toJSON(rapidjson::Document &doc) const override;
|
rapidjson::Value toJSON(rapidjson::Document &doc) const override;
|
||||||
|
|
||||||
|
inline Arch arch() const override { return m_arch; }
|
||||||
inline Assembly::Id assembly() const override { return m_assembly; }
|
inline Assembly::Id assembly() const override { return m_assembly; }
|
||||||
inline bool has(Flag flag) const override { return m_flags.test(flag); }
|
inline bool has(Flag flag) const override { return m_flags.test(flag); }
|
||||||
inline bool hasAES() const override { return has(FLAG_AES); }
|
inline bool hasAES() const override { return has(FLAG_AES); }
|
||||||
inline bool hasAVX() const override { return has(FLAG_AVX); }
|
inline bool hasAVX() const override { return has(FLAG_AVX); }
|
||||||
inline bool hasAVX2() const override { return has(FLAG_AVX2); }
|
inline bool hasAVX2() const override { return has(FLAG_AVX2); }
|
||||||
inline bool hasBMI2() const override { return has(FLAG_BMI2); }
|
inline bool hasBMI2() const override { return has(FLAG_BMI2); }
|
||||||
|
inline bool hasCatL3() const override { return has(FLAG_CAT_L3); }
|
||||||
inline bool hasOneGbPages() const override { return has(FLAG_PDPE1GB); }
|
inline bool hasOneGbPages() const override { return has(FLAG_PDPE1GB); }
|
||||||
inline bool hasXOP() const override { return has(FLAG_XOP); }
|
inline bool hasXOP() const override { return has(FLAG_XOP); }
|
||||||
inline bool hasCatL3() const override { return has(FLAG_CAT_L3); }
|
|
||||||
inline bool isVM() const override { return has(FLAG_VM); }
|
inline bool isVM() const override { return has(FLAG_VM); }
|
||||||
|
inline bool jccErratum() const override { return m_jccErratum; }
|
||||||
inline const char *brand() const override { return m_brand; }
|
inline const char *brand() const override { return m_brand; }
|
||||||
|
inline const std::vector<int32_t> &units() const override { return m_units; }
|
||||||
inline MsrMod msrMod() const override { return m_msrMod; }
|
inline MsrMod msrMod() const override { return m_msrMod; }
|
||||||
inline size_t cores() const override { return 0; }
|
inline size_t cores() const override { return 0; }
|
||||||
inline size_t L2() const override { return 0; }
|
inline size_t L2() const override { return 0; }
|
||||||
|
@ -64,15 +62,14 @@ protected:
|
||||||
inline size_t packages() const override { return 1; }
|
inline size_t packages() const override { return 1; }
|
||||||
inline size_t threads() const override { return m_threads; }
|
inline size_t threads() const override { return m_threads; }
|
||||||
inline Vendor vendor() const override { return m_vendor; }
|
inline Vendor vendor() const override { return m_vendor; }
|
||||||
inline Arch arch() const override { return m_arch; }
|
|
||||||
inline bool jccErratum() const override { return m_jccErratum; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
char m_brand[64 + 6]{};
|
|
||||||
size_t m_threads;
|
|
||||||
Vendor m_vendor = VENDOR_UNKNOWN;
|
|
||||||
Arch m_arch = ARCH_UNKNOWN;
|
Arch m_arch = ARCH_UNKNOWN;
|
||||||
bool m_jccErratum = false;
|
bool m_jccErratum = false;
|
||||||
|
char m_brand[64 + 6]{};
|
||||||
|
size_t m_threads;
|
||||||
|
std::vector<int32_t> m_units;
|
||||||
|
Vendor m_vendor = VENDOR_UNKNOWN;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
# ifndef XMRIG_ARM
|
# ifndef XMRIG_ARM
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* XMRig
|
/* XMRig
|
||||||
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
|
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||||
* Copyright (c) 2016-2020 XMRig <support@xmrig.com>
|
* Copyright (c) 2016-2021 XMRig <support@xmrig.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -170,7 +170,8 @@ xmrig::HwlocCpuInfo::HwlocCpuInfo()
|
||||||
|
|
||||||
findCache(root, 2, 3, [this](hwloc_obj_t found) { this->m_cache[found->attr->cache.depth] += found->attr->cache.size; });
|
findCache(root, 2, 3, [this](hwloc_obj_t found) { this->m_cache[found->attr->cache.depth] += found->attr->cache.size; });
|
||||||
|
|
||||||
m_threads = countByType(m_topology, HWLOC_OBJ_PU);
|
setThreads(countByType(m_topology, HWLOC_OBJ_PU));
|
||||||
|
|
||||||
m_cores = countByType(m_topology, HWLOC_OBJ_CORE);
|
m_cores = countByType(m_topology, HWLOC_OBJ_CORE);
|
||||||
m_nodes = std::max(hwloc_bitmap_weight(hwloc_topology_get_complete_nodeset(m_topology)), 1);
|
m_nodes = std::max(hwloc_bitmap_weight(hwloc_topology_get_complete_nodeset(m_topology)), 1);
|
||||||
m_packages = countByType(m_topology, HWLOC_OBJ_PACKAGE);
|
m_packages = countByType(m_topology, HWLOC_OBJ_PACKAGE);
|
||||||
|
@ -395,3 +396,20 @@ void xmrig::HwlocCpuInfo::processTopLevelCache(hwloc_obj_t cache, const Algorith
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void xmrig::HwlocCpuInfo::setThreads(size_t threads)
|
||||||
|
{
|
||||||
|
m_threads = threads;
|
||||||
|
|
||||||
|
if (m_units.size() != m_threads) {
|
||||||
|
m_units.resize(m_threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
hwloc_obj_t pu = nullptr;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
while ((pu = hwloc_get_next_obj_by_type(m_topology, HWLOC_OBJ_PU, pu)) != nullptr) {
|
||||||
|
m_units[i++] = static_cast<int32_t>(pu->os_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* XMRig
|
/* XMRig
|
||||||
* Copyright (c) 2018-2020 SChernykh <https://github.com/SChernykh>
|
* Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh>
|
||||||
* Copyright (c) 2016-2020 XMRig <support@xmrig.com>
|
* Copyright (c) 2016-2021 XMRig <support@xmrig.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -66,7 +66,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
CpuThreads allThreads(const Algorithm &algorithm, uint32_t limit) const;
|
CpuThreads allThreads(const Algorithm &algorithm, uint32_t limit) const;
|
||||||
void processTopLevelCache(hwloc_obj_t obj, const Algorithm &algorithm, CpuThreads &threads, size_t limit) const;
|
void processTopLevelCache(hwloc_obj_t obj, const Algorithm &algorithm, CpuThreads &threads, size_t limit) const;
|
||||||
|
void setThreads(size_t threads);
|
||||||
|
|
||||||
static uint32_t m_features;
|
static uint32_t m_features;
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,9 @@
|
||||||
#include "crypto/randomx/aes_hash.hpp"
|
#include "crypto/randomx/aes_hash.hpp"
|
||||||
|
|
||||||
|
|
||||||
#ifdef XMRIG_FIX_RYZEN
|
#ifdef XMRIG_FEATURE_MSR
|
||||||
# include "crypto/rx/RxFix.h"
|
# include "crypto/rx/RxFix.h"
|
||||||
|
# include "crypto/rx/RxMsr.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,8 +40,6 @@ class RxPrivate;
|
||||||
|
|
||||||
|
|
||||||
static bool osInitialized = false;
|
static bool osInitialized = false;
|
||||||
static bool msrInitialized = false;
|
|
||||||
static bool msrEnabled = false;
|
|
||||||
static RxPrivate *d_ptr = nullptr;
|
static RxPrivate *d_ptr = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,9 +69,9 @@ xmrig::RxDataset *xmrig::Rx::dataset(const Job &job, uint32_t nodeId)
|
||||||
|
|
||||||
void xmrig::Rx::destroy()
|
void xmrig::Rx::destroy()
|
||||||
{
|
{
|
||||||
if (osInitialized) {
|
# ifdef XMRIG_FEATURE_MSR
|
||||||
msrDestroy();
|
RxMsr::destroy();
|
||||||
}
|
# endif
|
||||||
|
|
||||||
delete d_ptr;
|
delete d_ptr;
|
||||||
|
|
||||||
|
@ -90,11 +89,9 @@ template<typename T>
|
||||||
bool xmrig::Rx::init(const T &seed, const RxConfig &config, const CpuConfig &cpu)
|
bool xmrig::Rx::init(const T &seed, const RxConfig &config, const CpuConfig &cpu)
|
||||||
{
|
{
|
||||||
if (seed.algorithm().family() != Algorithm::RANDOM_X) {
|
if (seed.algorithm().family() != Algorithm::RANDOM_X) {
|
||||||
if (msrInitialized) {
|
# ifdef XMRIG_FEATURE_MSR
|
||||||
msrDestroy();
|
RxMsr::destroy();
|
||||||
msrInitialized = false;
|
# endif
|
||||||
msrEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -103,10 +100,11 @@ bool xmrig::Rx::init(const T &seed, const RxConfig &config, const CpuConfig &cpu
|
||||||
randomx_set_huge_pages_jit(cpu.isHugePagesJit());
|
randomx_set_huge_pages_jit(cpu.isHugePagesJit());
|
||||||
randomx_set_optimized_dataset_init(config.initDatasetAVX2());
|
randomx_set_optimized_dataset_init(config.initDatasetAVX2());
|
||||||
|
|
||||||
if (!msrInitialized) {
|
# ifdef XMRIG_FEATURE_MSR
|
||||||
msrEnabled = msrInit(config, cpu.threads().get(seed.algorithm()).data());
|
if (!RxMsr::isInitialized()) {
|
||||||
msrInitialized = true;
|
RxMsr::init(config, cpu.threads().get(seed.algorithm()).data());
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
if (!osInitialized) {
|
if (!osInitialized) {
|
||||||
# ifdef XMRIG_FIX_RYZEN
|
# ifdef XMRIG_FIX_RYZEN
|
||||||
|
@ -139,24 +137,7 @@ bool xmrig::Rx::isReady(const T &seed)
|
||||||
#ifdef XMRIG_FEATURE_MSR
|
#ifdef XMRIG_FEATURE_MSR
|
||||||
bool xmrig::Rx::isMSR()
|
bool xmrig::Rx::isMSR()
|
||||||
{
|
{
|
||||||
return msrEnabled;
|
return RxMsr::isEnabled();
|
||||||
}
|
|
||||||
#else
|
|
||||||
bool xmrig::Rx::msrInit(const RxConfig &, const std::vector<CpuThread> &)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void xmrig::Rx::msrDestroy()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef XMRIG_FIX_RYZEN
|
|
||||||
void xmrig::Rx::setupMainLoopExceptionFrame()
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -57,10 +57,6 @@ public:
|
||||||
# else
|
# else
|
||||||
static constexpr bool isMSR() { return false; }
|
static constexpr bool isMSR() { return false; }
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
private:
|
|
||||||
static bool msrInit(const RxConfig &config, const std::vector<CpuThread>& threads);
|
|
||||||
static void msrDestroy();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
184
src/crypto/rx/RxMsr.cpp
Normal file
184
src/crypto/rx/RxMsr.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
53
src/crypto/rx/RxMsr.h
Normal file
53
src/crypto/rx/RxMsr.h
Normal file
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -55,6 +55,24 @@ std::shared_ptr<xmrig::Msr> xmrig::Msr::get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool xmrig::Msr::write(uint32_t reg, uint64_t value, int32_t cpu, uint64_t mask, bool verbose)
|
||||||
|
{
|
||||||
|
if (mask != MsrItem::kNoMask) {
|
||||||
|
uint64_t old_value;
|
||||||
|
if (rdmsr(reg, cpu, old_value)) {
|
||||||
|
value = MsrItem::maskedValue(old_value, value, mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool result = wrmsr(reg, value, cpu);
|
||||||
|
if (!result && verbose) {
|
||||||
|
LOG_WARN("%s " YELLOW_BOLD("cannot set MSR 0x%08" PRIx32 " to 0x%016" PRIx64), tag(), reg, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
xmrig::MsrItem xmrig::Msr::read(uint32_t reg, int32_t cpu, bool verbose) const
|
xmrig::MsrItem xmrig::Msr::read(uint32_t reg, int32_t cpu, bool verbose) const
|
||||||
{
|
{
|
||||||
uint64_t value = 0;
|
uint64_t value = 0;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "hw/msr/MsrItem.h"
|
#include "hw/msr/MsrItem.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,17 +40,24 @@ class Msr
|
||||||
public:
|
public:
|
||||||
XMRIG_DISABLE_COPY_MOVE(Msr)
|
XMRIG_DISABLE_COPY_MOVE(Msr)
|
||||||
|
|
||||||
|
using Callback = std::function<bool(int32_t cpu)>;
|
||||||
|
|
||||||
Msr();
|
Msr();
|
||||||
~Msr();
|
~Msr();
|
||||||
|
|
||||||
static const char *tag();
|
static const char *tag();
|
||||||
static std::shared_ptr<Msr> get();
|
static std::shared_ptr<Msr> get();
|
||||||
|
|
||||||
|
inline bool write(const MsrItem &item, int32_t cpu = -1, bool verbose = true) { return write(item.reg(), item.value(), cpu, item.mask(), verbose); }
|
||||||
|
|
||||||
bool isAvailable() const;
|
bool isAvailable() const;
|
||||||
|
bool write(uint32_t reg, uint64_t value, int32_t cpu = -1, uint64_t mask = MsrItem::kNoMask, bool verbose = true);
|
||||||
|
bool write(Callback &&callback);
|
||||||
MsrItem read(uint32_t reg, int32_t cpu = -1, bool verbose = true) const;
|
MsrItem read(uint32_t reg, int32_t cpu = -1, bool verbose = true) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool rdmsr(uint32_t reg, int32_t cpu, uint64_t &value) const;
|
bool rdmsr(uint32_t reg, int32_t cpu, uint64_t &value) const;
|
||||||
|
bool wrmsr(uint32_t reg, uint64_t value, int32_t cpu);
|
||||||
|
|
||||||
MsrPrivate *d_ptr = nullptr;
|
MsrPrivate *d_ptr = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,6 +46,11 @@ public:
|
||||||
inline uint64_t value() const { return m_value; }
|
inline uint64_t value() const { return m_value; }
|
||||||
inline uint64_t mask() const { return m_mask; }
|
inline uint64_t mask() const { return m_mask; }
|
||||||
|
|
||||||
|
static inline uint64_t maskedValue(uint64_t old_value, uint64_t new_value, uint64_t mask)
|
||||||
|
{
|
||||||
|
return (new_value & mask) | (old_value & ~mask);
|
||||||
|
}
|
||||||
|
|
||||||
rapidjson::Value toJSON(rapidjson::Document &doc) const;
|
rapidjson::Value toJSON(rapidjson::Document &doc) const;
|
||||||
String toString() const;
|
String toString() const;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "hw/msr/Msr.h"
|
#include "hw/msr/Msr.h"
|
||||||
#include "3rdparty/fmt/core.h"
|
#include "3rdparty/fmt/core.h"
|
||||||
|
#include "backend/cpu/Cpu.h"
|
||||||
#include "base/io/log/Log.h"
|
#include "base/io/log/Log.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,8 +32,6 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <ucontext.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace xmrig {
|
namespace xmrig {
|
||||||
|
@ -70,6 +69,20 @@ bool xmrig::Msr::isAvailable() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool xmrig::Msr::write(Callback &&callback)
|
||||||
|
{
|
||||||
|
const auto &units = Cpu::info()->units();
|
||||||
|
|
||||||
|
for (int32_t pu : units) {
|
||||||
|
if (!callback(pu)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool xmrig::Msr::rdmsr(uint32_t reg, int32_t cpu, uint64_t &value) const
|
bool xmrig::Msr::rdmsr(uint32_t reg, int32_t cpu, uint64_t &value) const
|
||||||
{
|
{
|
||||||
const auto name = fmt::format("/dev/cpu/{}/msr", cpu < 0 ? 0 : cpu);
|
const auto name = fmt::format("/dev/cpu/{}/msr", cpu < 0 ? 0 : cpu);
|
||||||
|
@ -84,3 +97,20 @@ bool xmrig::Msr::rdmsr(uint32_t reg, int32_t cpu, uint64_t &value) const
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool xmrig::Msr::wrmsr(uint32_t reg, uint64_t value, int32_t cpu)
|
||||||
|
{
|
||||||
|
const auto name = fmt::format("/dev/cpu/{}/msr", cpu < 0 ? 0 : cpu);
|
||||||
|
int fd = open(name.c_str(), O_WRONLY);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool success = pwrite(fd, &value, sizeof value, reg) == sizeof value;
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
|
@ -18,10 +18,13 @@
|
||||||
|
|
||||||
|
|
||||||
#include "hw/msr/Msr.h"
|
#include "hw/msr/Msr.h"
|
||||||
|
#include "backend/cpu/Cpu.h"
|
||||||
#include "base/io/log/Log.h"
|
#include "base/io/log/Log.h"
|
||||||
|
#include "base/kernel/Platform.h"
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
@ -196,9 +199,57 @@ bool xmrig::Msr::isAvailable() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool xmrig::Msr::rdmsr(uint32_t reg, int32_t, uint64_t &value) const
|
bool xmrig::Msr::write(Callback &&callback)
|
||||||
{
|
{
|
||||||
|
const auto &units = Cpu::info()->units();
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
std::thread thread([&callback, &units, &success]() {
|
||||||
|
for (int32_t pu : units) {
|
||||||
|
if (!Platform::setThreadAffinity(pu)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!callback(pu)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
success = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
thread.join();
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool xmrig::Msr::rdmsr(uint32_t reg, int32_t cpu, uint64_t &value) const
|
||||||
|
{
|
||||||
|
assert(cpu < 0);
|
||||||
|
|
||||||
DWORD size = 0;
|
DWORD size = 0;
|
||||||
|
|
||||||
return DeviceIoControl(d_ptr->driver, IOCTL_READ_MSR, ®, sizeof(reg), &value, sizeof(value), &size, nullptr) != 0;
|
return DeviceIoControl(d_ptr->driver, IOCTL_READ_MSR, ®, sizeof(reg), &value, sizeof(value), &size, nullptr) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool xmrig::Msr::wrmsr(uint32_t reg, uint64_t value, int32_t cpu)
|
||||||
|
{
|
||||||
|
assert(cpu < 0);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t reg = 0;
|
||||||
|
uint32_t value[2]{};
|
||||||
|
} input;
|
||||||
|
|
||||||
|
static_assert(sizeof(input) == 12, "Invalid struct size for WinRing0 driver");
|
||||||
|
|
||||||
|
input.reg = reg;
|
||||||
|
*(reinterpret_cast<uint64_t*>(input.value)) = value;
|
||||||
|
|
||||||
|
DWORD output;
|
||||||
|
DWORD k;
|
||||||
|
|
||||||
|
return DeviceIoControl(d_ptr->driver, IOCTL_WRITE_MSR, &input, sizeof(input), &output, sizeof(output), &k, nullptr) != 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue