diff --git a/CMakeLists.txt b/CMakeLists.txt
index 35fba8ea5..79486e03e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,6 +26,7 @@ option(WITH_PROFILING       "Enable profiling for developers" OFF)
 option(WITH_SSE4_1          "Enable SSE 4.1 for Blake2" ON)
 option(WITH_BENCHMARK       "Enable builtin RandomX benchmark and stress test" ON)
 option(WITH_SECURE_JIT      "Enable secure access to JIT memory" OFF)
+option(WITH_DMI             "Enable DMI/SMBIOS reader" OFF)
 
 option(BUILD_STATIC         "Build static binary" OFF)
 option(ARM_TARGET           "Force use specific ARM target 8 or 7" 0)
@@ -169,7 +170,7 @@ else()
 endif()
 
 add_definitions(-DXMRIG_MINER_PROJECT -DXMRIG_JSON_SINGLE_LINE_ARRAY)
-add_definitions(-D__STDC_FORMAT_MACROS -DUNICODE)
+add_definitions(-D__STDC_FORMAT_MACROS -DUNICODE -D_FILE_OFFSET_BITS=64)
 
 find_package(UV REQUIRED)
 
@@ -197,6 +198,9 @@ if (WITH_EMBEDDED_CONFIG)
     add_definitions(/DXMRIG_FEATURE_EMBEDDED_CONFIG)
 endif()
 
+include(src/hw/api/api.cmake)
+include(src/hw/dmi/dmi.cmake)
+
 include_directories(src)
 include_directories(src/3rdparty)
 include_directories(${UV_INCLUDE_DIR})
diff --git a/src/Summary.cpp b/src/Summary.cpp
index ebaeb3563..eaee89bf5 100644
--- a/src/Summary.cpp
+++ b/src/Summary.cpp
@@ -5,8 +5,8 @@
  * 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>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 2016-2021 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
@@ -39,6 +39,11 @@
 #include "version.h"
 
 
+#ifdef XMRIG_FEATURE_DMI
+#   include "hw/dmi/DmiReader.h"
+#endif
+
+
 #ifdef XMRIG_ALGO_RANDOMX
 #   include "crypto/rx/RxConfig.h"
 #endif
@@ -71,7 +76,7 @@ inline static const char *asmName(Assembly::Id assembly)
 #endif
 
 
-static void print_memory(Config *config)
+static void print_pages(const Config *config)
 {
     Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") "%s",
                "HUGE PAGES", config->cpu().isHugePages() ? (VirtualMemory::isHugepagesAvailable() ? kHugepagesSupported : RED_BOLD("unavailable")) : RED_BOLD("disabled"));
@@ -87,7 +92,7 @@ static void print_memory(Config *config)
 }
 
 
-static void print_cpu(Config *)
+static void print_cpu(const Config *)
 {
     const auto info = Cpu::info();
 
@@ -116,7 +121,7 @@ static void print_cpu(Config *)
 }
 
 
-static void print_memory()
+static void print_memory(const Config *config)
 {
     constexpr size_t oneGiB = 1024U * 1024U * 1024U;
     const auto freeMem      = static_cast<double>(uv_get_free_memory());
@@ -124,16 +129,49 @@ static void print_memory()
 
     const double percent = freeMem > 0 ? ((totalMem - freeMem) / totalMem * 100.0) : 100.0;
 
-    Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%.1f/%.1f GB") BLACK_BOLD(" (%.0f%%)"),
+    Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") CYAN_BOLD("%.1f/%.1f") CYAN(" GB") BLACK_BOLD(" (%.0f%%)"),
                "MEMORY",
                (totalMem - freeMem) / oneGiB,
                totalMem / oneGiB,
                percent
                );
+
+#   ifdef XMRIG_FEATURE_DMI
+    if (!config->isDMI()) {
+        return;
+    }
+
+    DmiReader reader;
+    if (!reader.read()) {
+        return;
+    }
+
+    const bool vm = Cpu::info()->isVM();
+
+    for (const auto &memory : reader.memory()) {
+        if (!memory.isValid()) {
+            continue;
+        }
+
+        if (memory.size()) {
+            Log::print(WHITE_BOLD("   %-13s") "%s: " CYAN_BOLD("%" PRIu64) CYAN(" GB ") WHITE_BOLD("%s @ %" PRIu64 " MHz ") BLACK_BOLD("%s"),
+                       "", memory.slot().data(), memory.size() / oneGiB, memory.type(), memory.speed() / 1000000ULL, memory.product().data());
+        }
+        else if (!vm) {
+            Log::print(WHITE_BOLD("   %-13s") "%s: " BLACK_BOLD("<empty>"), "", memory.slot().data());
+        }
+    }
+
+    const auto &board = vm ? reader.system() : reader.board();
+
+    if (board.isValid()) {
+        Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s") " - " WHITE_BOLD("%s"), "MOTHERBOARD", board.vendor().data(), board.product().data());
+    }
+#   endif
 }
 
 
-static void print_threads(Config *config)
+static void print_threads(const Config *config)
 {
     Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s%d%%"),
                "DONATE",
@@ -175,14 +213,16 @@ static void print_commands(Config *)
 
 void xmrig::Summary::print(Controller *controller)
 {
-    controller->config()->printVersions();
-    print_memory(controller->config());
-    print_cpu(controller->config());
-    print_memory();
-    print_threads(controller->config());
-    controller->config()->pools().print();
+    const auto config = controller->config();
 
-    print_commands(controller->config());
+    config->printVersions();
+    print_pages(config);
+    print_cpu(config);
+    print_memory(config);
+    print_threads(config);
+    config->pools().print();
+
+    print_commands(config);
 }
 
 
diff --git a/src/Summary.h b/src/Summary.h
index 4317d13e1..0b03f6759 100644
--- a/src/Summary.h
+++ b/src/Summary.h
@@ -5,8 +5,8 @@
  * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
  * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
  * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2019 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2019 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
diff --git a/src/base/api/Api.cpp b/src/base/api/Api.cpp
index 89e61593c..3a71fd9c3 100644
--- a/src/base/api/Api.cpp
+++ b/src/base/api/Api.cpp
@@ -1,12 +1,6 @@
 /* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
diff --git a/src/base/api/Api.h b/src/base/api/Api.h
index 0ee9ca6ae..f412a3172 100644
--- a/src/base/api/Api.h
+++ b/src/base/api/Api.h
@@ -1,12 +1,6 @@
 /* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2019 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2019 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -31,7 +25,6 @@
 
 
 #include "base/kernel/interfaces/IBaseListener.h"
-#include "base/tools/Object.h"
 #include "base/tools/String.h"
 
 
diff --git a/src/base/api/interfaces/IApiListener.h b/src/base/api/interfaces/IApiListener.h
index bbf153a69..71ee9c76d 100644
--- a/src/base/api/interfaces/IApiListener.h
+++ b/src/base/api/interfaces/IApiListener.h
@@ -1,10 +1,6 @@
 /* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2016-2018 XMRig       <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -24,6 +20,9 @@
 #define XMRIG_IAPILISTENER_H
 
 
+#include "base/tools/Object.h"
+
+
 namespace xmrig {
 
 
@@ -33,6 +32,9 @@ class IApiRequest;
 class IApiListener
 {
 public:
+    XMRIG_DISABLE_COPY_MOVE(IApiListener)
+
+    IApiListener()          = default;
     virtual ~IApiListener() = default;
 
 #   ifdef XMRIG_FEATURE_API
diff --git a/src/base/api/interfaces/IApiRequest.h b/src/base/api/interfaces/IApiRequest.h
index c05e513ec..35fb27d5f 100644
--- a/src/base/api/interfaces/IApiRequest.h
+++ b/src/base/api/interfaces/IApiRequest.h
@@ -1,12 +1,6 @@
 /* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -27,6 +21,7 @@
 
 
 #include "3rdparty/rapidjson/fwd.h"
+#include "base/tools/Object.h"
 
 
 namespace xmrig {
@@ -38,6 +33,8 @@ class String;
 class IApiRequest
 {
 public:
+    XMRIG_DISABLE_COPY_MOVE(IApiRequest)
+
     enum Method {
         METHOD_DELETE,
         METHOD_GET,
@@ -67,7 +64,8 @@ public:
     };
 
 
-    virtual ~IApiRequest() = default;
+    IApiRequest()           = default;
+    virtual ~IApiRequest()  = default;
 
     virtual bool accept()                                               = 0;
     virtual bool hasParseError() const                                  = 0;
diff --git a/src/base/kernel/interfaces/IBaseListener.h b/src/base/kernel/interfaces/IBaseListener.h
index 1f2123690..80120ab85 100644
--- a/src/base/kernel/interfaces/IBaseListener.h
+++ b/src/base/kernel/interfaces/IBaseListener.h
@@ -1,12 +1,6 @@
 /* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2019 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2019 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -26,6 +20,9 @@
 #define XMRIG_IBASELISTENER_H
 
 
+#include "base/tools/Object.h"
+
+
 namespace xmrig {
 
 
@@ -35,7 +32,10 @@ class Config;
 class IBaseListener
 {
 public:
-    virtual ~IBaseListener() = default;
+    XMRIG_DISABLE_COPY_MOVE(IBaseListener)
+
+    IBaseListener()             = default;
+    virtual ~IBaseListener()    = default;
 
     virtual void onConfigChanged(Config *config, Config *previousConfig) = 0;
 };
diff --git a/src/base/kernel/interfaces/IConfig.h b/src/base/kernel/interfaces/IConfig.h
index 8b5ae278a..792c43a11 100644
--- a/src/base/kernel/interfaces/IConfig.h
+++ b/src/base/kernel/interfaces/IConfig.h
@@ -5,8 +5,8 @@
  * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
  * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
  * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -84,6 +84,7 @@ public:
         BenchSeedKey         = 1046,
         BenchHashKey         = 1047,
         BenchTokenKey        = 1048,
+        DmiKey               = 1049,
 
         // xmrig common
         CPUPriorityKey       = 1021,
diff --git a/src/base/net/stratum/Pools.cpp b/src/base/net/stratum/Pools.cpp
index a9c245fa3..d2ab30126 100644
--- a/src/base/net/stratum/Pools.cpp
+++ b/src/base/net/stratum/Pools.cpp
@@ -5,8 +5,8 @@
  * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
  * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
  * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -134,7 +134,7 @@ void xmrig::Pools::load(const IJsonReader &reader)
     m_data.clear();
 
 #   ifdef XMRIG_FEATURE_BENCHMARK
-    m_benchmark = std::shared_ptr<BenchConfig>(BenchConfig::create(reader.getObject(BenchConfig::kBenchmark)));
+    m_benchmark = std::shared_ptr<BenchConfig>(BenchConfig::create(reader.getObject(BenchConfig::kBenchmark), reader.getBool("dmi", true)));
     if (m_benchmark) {
         m_data.emplace_back(m_benchmark);
 
diff --git a/src/base/net/stratum/Pools.h b/src/base/net/stratum/Pools.h
index 477ce211b..7fa6ec9d5 100644
--- a/src/base/net/stratum/Pools.h
+++ b/src/base/net/stratum/Pools.h
@@ -5,8 +5,8 @@
  * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
  * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
  * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
diff --git a/src/base/net/stratum/benchmark/BenchClient.cpp b/src/base/net/stratum/benchmark/BenchClient.cpp
index c81f40105..0e1093a11 100644
--- a/src/base/net/stratum/benchmark/BenchClient.cpp
+++ b/src/base/net/stratum/benchmark/BenchClient.cpp
@@ -1,6 +1,6 @@
 /* XMRig
- * Copyright (c) 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.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
@@ -34,6 +34,10 @@
 #include "base/tools/Cvt.h"
 #include "version.h"
 
+#ifdef XMRIG_FEATURE_DMI
+#   include "hw/dmi/DmiReader.h"
+#endif
+
 
 xmrig::BenchClient::BenchClient(const std::shared_ptr<BenchConfig> &benchmark, IClientListener* listener) :
     m_listener(listener),
@@ -336,6 +340,15 @@ void xmrig::BenchClient::send(Request request)
             doc.AddMember("steady_ready_ts",                m_readyTime, allocator);
             doc.AddMember("cpu",                            Cpu::toJSON(doc), allocator);
 
+#           ifdef XMRIG_FEATURE_DMI
+            if (m_benchmark->isDMI()) {
+                DmiReader reader;
+                if (reader.read()) {
+                    doc.AddMember("dmi", reader.toJSON(doc), allocator);
+                }
+            }
+#           endif
+
             FetchRequest req(HTTP_POST, m_ip, BenchConfig::kApiPort, "/1/benchmark", doc, BenchConfig::kApiTLS, true);
             fetch(tag(), std::move(req), m_httpListener);
         }
diff --git a/src/base/net/stratum/benchmark/BenchClient.h b/src/base/net/stratum/benchmark/BenchClient.h
index 018bceaaf..7eac1ee87 100644
--- a/src/base/net/stratum/benchmark/BenchClient.h
+++ b/src/base/net/stratum/benchmark/BenchClient.h
@@ -1,6 +1,6 @@
 /* XMRig
- * Copyright (c) 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.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
diff --git a/src/base/net/stratum/benchmark/BenchConfig.cpp b/src/base/net/stratum/benchmark/BenchConfig.cpp
index 2e02755a1..c81e0c172 100644
--- a/src/base/net/stratum/benchmark/BenchConfig.cpp
+++ b/src/base/net/stratum/benchmark/BenchConfig.cpp
@@ -1,6 +1,6 @@
 /* XMRig
- * Copyright (c) 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.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
@@ -52,8 +52,9 @@ const char *BenchConfig::kApiHost   = "127.0.0.1";
 } // namespace xmrig
 
 
-xmrig::BenchConfig::BenchConfig(uint32_t size, const String &id, const rapidjson::Value &object) :
+xmrig::BenchConfig::BenchConfig(uint32_t size, const String &id, const rapidjson::Value &object, bool dmi) :
     m_algorithm(Json::getString(object, kAlgo)),
+    m_dmi(dmi),
     m_submit(Json::getBool(object, kSubmit)),
     m_id(id),
     m_seed(Json::getString(object, kSeed)),
@@ -72,7 +73,7 @@ xmrig::BenchConfig::BenchConfig(uint32_t size, const String &id, const rapidjson
 }
 
 
-xmrig::BenchConfig *xmrig::BenchConfig::create(const rapidjson::Value &object)
+xmrig::BenchConfig *xmrig::BenchConfig::create(const rapidjson::Value &object, bool dmi)
 {
     if (!object.IsObject() || object.ObjectEmpty()) {
         return nullptr;
@@ -85,7 +86,7 @@ xmrig::BenchConfig *xmrig::BenchConfig::create(const rapidjson::Value &object)
         return nullptr;
     }
 
-    return new BenchConfig(size, id, object);
+    return new BenchConfig(size, id, object, dmi);
 }
 
 
diff --git a/src/base/net/stratum/benchmark/BenchConfig.h b/src/base/net/stratum/benchmark/BenchConfig.h
index f1310236f..87e541972 100644
--- a/src/base/net/stratum/benchmark/BenchConfig.h
+++ b/src/base/net/stratum/benchmark/BenchConfig.h
@@ -1,6 +1,6 @@
 /* XMRig
- * Copyright (c) 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.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
@@ -49,10 +49,11 @@ public:
     static constexpr const uint16_t kApiPort    = 18805;
 #   endif
 
-    BenchConfig(uint32_t size, const String &id, const rapidjson::Value &object);
+    BenchConfig(uint32_t size, const String &id, const rapidjson::Value &object, bool dmi);
 
-    static BenchConfig *create(const rapidjson::Value &object);
+    static BenchConfig *create(const rapidjson::Value &object, bool dmi);
 
+    inline bool isDMI() const                   { return m_dmi; }
     inline bool isSubmit() const                { return m_submit; }
     inline const Algorithm &algorithm() const   { return m_algorithm; }
     inline const String &id() const             { return m_id; }
@@ -67,6 +68,7 @@ private:
     static uint32_t getSize(const char *benchmark);
 
     Algorithm m_algorithm;
+    bool m_dmi;
     bool m_submit;
     String m_id;
     String m_seed;
diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp
index 8f230e002..40c3aeac4 100644
--- a/src/core/Controller.cpp
+++ b/src/core/Controller.cpp
@@ -1,12 +1,6 @@
 /* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2019 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2019 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -31,6 +25,12 @@
 #include "net/Network.h"
 
 
+#ifdef XMRIG_FEATURE_API
+#   include "base/api/Api.h"
+#   include "hw/api/HwApi.h"
+#endif
+
+
 #include <cassert>
 
 
@@ -42,8 +42,6 @@ xmrig::Controller::Controller(Process *process) :
 
 xmrig::Controller::~Controller()
 {
-    delete m_network;
-
     VirtualMemory::destroy();
 }
 
@@ -54,7 +52,12 @@ int xmrig::Controller::init()
 
     VirtualMemory::init(config()->cpu().memPoolSize(), config()->cpu().isHugePages());
 
-    m_network = new Network(this);
+    m_network = std::make_shared<Network>(this);
+
+#   ifdef XMRIG_FEATURE_API
+    m_hwApi = std::make_shared<HwApi>();
+    api()->addListener(m_hwApi.get());
+#   endif
 
     return 0;
 }
@@ -64,7 +67,7 @@ void xmrig::Controller::start()
 {
     Base::start();
 
-    m_miner = new Miner(this);
+    m_miner = std::make_shared<Miner>(this);
 
     network()->connect();
 }
@@ -74,29 +77,26 @@ void xmrig::Controller::stop()
 {
     Base::stop();
 
-    delete m_network;
-    m_network = nullptr;
+    m_network.reset();
 
     m_miner->stop();
-
-    delete m_miner;
-    m_miner = nullptr;
+    m_miner.reset();
 }
 
 
 xmrig::Miner *xmrig::Controller::miner() const
 {
-    assert(m_miner != nullptr);
+    assert(m_miner);
 
-    return m_miner;
+    return m_miner.get();
 }
 
 
 xmrig::Network *xmrig::Controller::network() const
 {
-    assert(m_network != nullptr);
+    assert(m_network);
 
-    return m_network;
+    return m_network.get();
 }
 
 
diff --git a/src/core/Controller.h b/src/core/Controller.h
index 947084734..13704f151 100644
--- a/src/core/Controller.h
+++ b/src/core/Controller.h
@@ -1,12 +1,6 @@
 /* XMRig
- * Copyright 2010      Jeff Garzik <jgarzik@pobox.com>
- * Copyright 2012-2014 pooler      <pooler@litecoinpool.org>
- * Copyright 2014      Lucas Jones <https://github.com/lucasjones>
- * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
- * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
- * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2019 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2019 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -27,12 +21,15 @@
 
 
 #include "base/kernel/Base.h"
-#include "base/tools/Object.h"
+
+
+#include <memory>
 
 
 namespace xmrig {
 
 
+class HwApi;
 class Job;
 class Miner;
 class Network;
@@ -55,8 +52,12 @@ public:
     void execCommand(char command);
 
 private:
-    Miner *m_miner     = nullptr;
-    Network *m_network = nullptr;
+    std::shared_ptr<Miner> m_miner;
+    std::shared_ptr<Network> m_network;
+
+#   ifdef XMRIG_FEATURE_API
+    std::shared_ptr<HwApi> m_hwApi;
+#   endif
 };
 
 
diff --git a/src/core/config/Config.cpp b/src/core/config/Config.cpp
index 792b3873d..f8b7bb858 100644
--- a/src/core/config/Config.cpp
+++ b/src/core/config/Config.cpp
@@ -5,8 +5,8 @@
  * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
  * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
  * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -23,9 +23,9 @@
  */
 
 #include <algorithm>
+#include <cinttypes>
 #include <cstring>
 #include <uv.h>
-#include <cinttypes>
 
 
 #include "core/config/Config.h"
@@ -55,16 +55,19 @@ namespace xmrig {
 
 
 #ifdef XMRIG_FEATURE_OPENCL
-static const char *kOcl     = "opencl";
+const char *Config::kOcl                = "opencl";
 #endif
 
 #ifdef XMRIG_FEATURE_CUDA
-static const char *kCuda    = "cuda";
+const char *Config::kCuda               = "cuda";
 #endif
 
-
 #if defined(XMRIG_FEATURE_NVML) || defined (XMRIG_FEATURE_ADL)
-static const char *kHealthPrintTime = "health-print-time";
+const char *Config::kHealthPrintTime    = "health-print-time";
+#endif
+
+#ifdef XMRIG_FEATURE_DMI
+const char *Config::kDMI                = "dmi";
 #endif
 
 
@@ -88,6 +91,10 @@ public:
 #   if defined(XMRIG_FEATURE_NVML) || defined (XMRIG_FEATURE_ADL)
     uint32_t healthPrintTime = 60;
 #   endif
+
+#   ifdef XMRIG_FEATURE_DMI
+    bool dmi = true;
+#   endif
 };
 
 }
@@ -143,6 +150,14 @@ uint32_t xmrig::Config::healthPrintTime() const
 #endif
 
 
+#ifdef XMRIG_FEATURE_DMI
+bool xmrig::Config::isDMI() const
+{
+    return d_ptr->dmi;
+}
+#endif
+
+
 bool xmrig::Config::isShouldSave() const
 {
     if (!isAutoSave()) {
@@ -191,6 +206,10 @@ bool xmrig::Config::read(const IJsonReader &reader, const char *fileName)
     d_ptr->healthPrintTime = reader.getUint(kHealthPrintTime, d_ptr->healthPrintTime);
 #   endif
 
+#   ifdef XMRIG_FEATURE_DMI
+    d_ptr->dmi = reader.getBool(kDMI, d_ptr->dmi);
+#   endif
+
     return true;
 }
 
@@ -236,6 +255,11 @@ void xmrig::Config::getJSON(rapidjson::Document &doc) const
 #   if defined(XMRIG_FEATURE_NVML) || defined (XMRIG_FEATURE_ADL)
     doc.AddMember(StringRef(kHealthPrintTime),          healthPrintTime(), allocator);
 #   endif
+
+#   ifdef XMRIG_FEATURE_DMI
+    doc.AddMember(StringRef(kDMI),                      isDMI(), allocator);
+#   endif
+
     doc.AddMember(StringRef(kSyslog),                   isSyslog(), allocator);
 
 #   ifdef XMRIG_FEATURE_TLS
diff --git a/src/core/config/Config.h b/src/core/config/Config.h
index 501b8c592..d8433beb2 100644
--- a/src/core/config/Config.h
+++ b/src/core/config/Config.h
@@ -5,8 +5,8 @@
  * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
  * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
  * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -50,6 +50,22 @@ class Config : public BaseConfig
 public:
     XMRIG_DISABLE_COPY_MOVE(Config);
 
+#   ifdef XMRIG_FEATURE_OPENCL
+    static const char *kOcl;
+#   endif
+
+#   ifdef XMRIG_FEATURE_CUDA
+    static const char *kCuda;
+#   endif
+
+#   if defined(XMRIG_FEATURE_NVML) || defined (XMRIG_FEATURE_ADL)
+    static const char *kHealthPrintTime;
+#   endif
+
+#   ifdef XMRIG_FEATURE_DMI
+    static const char *kDMI;
+#   endif
+
     Config();
     ~Config() override;
 
@@ -70,7 +86,13 @@ public:
 #   if defined(XMRIG_FEATURE_NVML) || defined (XMRIG_FEATURE_ADL)
     uint32_t healthPrintTime() const;
 #   else
-    uint32_t healthPrintTime() const { return 0; }
+    uint32_t healthPrintTime() const        { return 0; }
+#   endif
+
+#   ifdef XMRIG_FEATURE_DMI
+    bool isDMI() const;
+#   else
+    static constexpr inline bool isDMI()    { return false; }
 #   endif
 
     bool isShouldSave() const;
diff --git a/src/core/config/ConfigTransform.cpp b/src/core/config/ConfigTransform.cpp
index b8a431fd1..b32aede37 100644
--- a/src/core/config/ConfigTransform.cpp
+++ b/src/core/config/ConfigTransform.cpp
@@ -5,8 +5,8 @@
  * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
  * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
  * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
@@ -23,11 +23,11 @@
  */
 
 
+#include "core/config/ConfigTransform.h"
 #include "base/kernel/interfaces/IConfig.h"
-#include "backend/cpu/CpuConfig.h"
 #include "base/net/stratum/Pool.h"
 #include "base/net/stratum/Pools.h"
-#include "core/config/ConfigTransform.h"
+#include "core/config/Config.h"
 #include "crypto/cn/CnHash.h"
 
 
@@ -51,14 +51,6 @@ static const char *kEnabled     = "enabled";
 static const char *kIntensity   = "intensity";
 static const char *kThreads     = "threads";
 
-#ifdef XMRIG_FEATURE_OPENCL
-static const char *kOcl         = "opencl";
-#endif
-
-#ifdef XMRIG_FEATURE_CUDA
-static const char *kCuda        = "cuda";
-#endif
-
 
 static inline uint64_t intensity(uint64_t av)
 {
@@ -122,7 +114,7 @@ void xmrig::ConfigTransform::finalize(rapidjson::Document &doc)
 
 #   ifdef XMRIG_FEATURE_OPENCL
     if (m_opencl) {
-        set(doc, kOcl, kEnabled, true);
+        set(doc, Config::kOcl, kEnabled, true);
     }
 #   endif
 }
@@ -208,47 +200,54 @@ void xmrig::ConfigTransform::transform(rapidjson::Document &doc, int key, const
         break;
 
     case IConfig::OclCacheKey: /* --opencl-no-cache */
-        return set(doc, kOcl, "cache", false);
+        return set(doc, Config::kOcl, "cache", false);
 
     case IConfig::OclLoaderKey: /* --opencl-loader */
-        return set(doc, kOcl, "loader", arg);
+        return set(doc, Config::kOcl, "loader", arg);
 
     case IConfig::OclDevicesKey: /* --opencl-devices */
         m_opencl = true;
-        return set(doc, kOcl, "devices-hint", arg);
+        return set(doc, Config::kOcl, "devices-hint", arg);
 
     case IConfig::OclPlatformKey: /* --opencl-platform */
         if (strlen(arg) < 3) {
-            return set(doc, kOcl, "platform", static_cast<uint64_t>(strtol(arg, nullptr, 10)));
+            return set(doc, Config::kOcl, "platform", static_cast<uint64_t>(strtol(arg, nullptr, 10)));
         }
 
-        return set(doc, kOcl, "platform", arg);
+        return set(doc, Config::kOcl, "platform", arg);
 #   endif
 
 #   ifdef XMRIG_FEATURE_CUDA
     case IConfig::CudaKey: /* --cuda */
-        return set(doc, kCuda, kEnabled, true);
+        return set(doc, Config::kCuda, kEnabled, true);
 
     case IConfig::CudaLoaderKey: /* --cuda-loader */
-        return set(doc, kCuda, "loader", arg);
+        return set(doc, Config::kCuda, "loader", arg);
 
     case IConfig::CudaDevicesKey: /* --cuda-devices */
-        set(doc, kCuda, kEnabled, true);
-        return set(doc, kCuda, "devices-hint", arg);
+        set(doc, Config::kCuda, kEnabled, true);
+        return set(doc, Config::kCuda, "devices-hint", arg);
 
     case IConfig::CudaBFactorKey: /* --cuda-bfactor-hint */
-        return set(doc, kCuda, "bfactor-hint", static_cast<uint64_t>(strtol(arg, nullptr, 10)));
+        return set(doc, Config::kCuda, "bfactor-hint", static_cast<uint64_t>(strtol(arg, nullptr, 10)));
 
     case IConfig::CudaBSleepKey: /* --cuda-bsleep-hint */
-        return set(doc, kCuda, "bsleep-hint", static_cast<uint64_t>(strtol(arg, nullptr, 10)));
+        return set(doc, Config::kCuda, "bsleep-hint", static_cast<uint64_t>(strtol(arg, nullptr, 10)));
 #   endif
 
 #   ifdef XMRIG_FEATURE_NVML
     case IConfig::NvmlKey: /* --no-nvml */
-        return set(doc, kCuda, "nvml", false);
+        return set(doc, Config::kCuda, "nvml", false);
+#   endif
 
+#   if defined(XMRIG_FEATURE_NVML) || defined (XMRIG_FEATURE_ADL)
     case IConfig::HealthPrintTimeKey: /* --health-print-time */
-        return set(doc, "health-print-time", static_cast<uint64_t>(strtol(arg, nullptr, 10)));
+        return set(doc, Config::kHealthPrintTime, static_cast<uint64_t>(strtol(arg, nullptr, 10)));
+#   endif
+
+#   ifdef XMRIG_FEATURE_DMI
+    case IConfig::DmiKey: /* --no-dmi */
+        return set(doc, Config::kDMI, false);
 #   endif
 
 #   ifdef XMRIG_FEATURE_BENCHMARK
diff --git a/src/core/config/ConfigTransform.h b/src/core/config/ConfigTransform.h
index 0251777ce..8fd2505ce 100644
--- a/src/core/config/ConfigTransform.h
+++ b/src/core/config/ConfigTransform.h
@@ -5,8 +5,8 @@
  * Copyright 2014-2016 Wolf9466    <https://github.com/OhGodAPet>
  * Copyright 2016      Jay D Dee   <jayddee246@gmail.com>
  * Copyright 2017-2018 XMR-Stak    <https://github.com/fireice-uk>, <https://github.com/psychocrypt>
- * Copyright 2018-2020 SChernykh   <https://github.com/SChernykh>
- * Copyright 2016-2020 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * Copyright 2018-2021 SChernykh   <https://github.com/SChernykh>
+ * Copyright 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
diff --git a/src/core/config/Config_platform.h b/src/core/config/Config_platform.h
index f698836c4..b6fcd1c1a 100644
--- a/src/core/config/Config_platform.h
+++ b/src/core/config/Config_platform.h
@@ -155,7 +155,12 @@ static const option options[] = {
 #   endif
 #   ifdef XMRIG_FEATURE_NVML
     { "no-nvml",               0, nullptr, IConfig::NvmlKey               },
+#   endif
+#   if defined(XMRIG_FEATURE_NVML) || defined (XMRIG_FEATURE_ADL)
     { "health-print-time",     1, nullptr, IConfig::HealthPrintTimeKey    },
+#   endif
+#   ifdef XMRIG_FEATURE_DMI
+    { "no-dmi",                0, nullptr, IConfig::DmiKey                },
 #   endif
     { nullptr,                 0, nullptr, 0 }
 };
diff --git a/src/core/config/usage.h b/src/core/config/usage.h
index 54e629ecb..261e571cf 100644
--- a/src/core/config/usage.h
+++ b/src/core/config/usage.h
@@ -190,6 +190,10 @@ static inline const std::string &usage()
     u += "      --hash=HASH               compare benchmark result with specified hash\n";
 #   endif
 
+#   ifdef XMRIG_FEATURE_DMI
+    u += "      --no-dmi                  disable DMI/SMBIOS reader\n";
+#   endif
+
     return u;
 }
 
diff --git a/src/hw/api/HwApi.cpp b/src/hw/api/HwApi.cpp
new file mode 100644
index 000000000..fed5de3f9
--- /dev/null
+++ b/src/hw/api/HwApi.cpp
@@ -0,0 +1,45 @@
+/* XMRig
+ * 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 "hw/api/HwApi.h"
+#include "base/api/interfaces/IApiRequest.h"
+#include "base/tools/String.h"
+
+
+#ifdef XMRIG_FEATURE_DMI
+#   include "hw/dmi/DmiReader.h"
+#endif
+
+
+void xmrig::HwApi::onRequest(IApiRequest &request)
+{
+    if (request.method() == IApiRequest::METHOD_GET) {
+#       ifdef XMRIG_FEATURE_DMI
+        if (request.url() == "/2/dmi") {
+            if (!m_dmi) {
+                m_dmi = std::make_shared<DmiReader>();
+                m_dmi->read();
+            }
+
+            request.accept();
+            m_dmi->toJSON(request.reply(), request.doc());
+        }
+#       endif
+    }
+}
diff --git a/src/hw/api/HwApi.h b/src/hw/api/HwApi.h
new file mode 100644
index 000000000..f434a0a5a
--- /dev/null
+++ b/src/hw/api/HwApi.h
@@ -0,0 +1,53 @@
+/* XMRig
+ * 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_HWAPI_H
+#define XMRIG_HWAPI_H
+
+
+#include "base/api/interfaces/IApiListener.h"
+
+
+#include <memory>
+
+
+namespace xmrig {
+
+
+struct DmiReader;
+
+
+class HwApi : public IApiListener
+{
+public:
+    HwApi() = default;
+
+protected:
+    void onRequest(IApiRequest &request) override;
+
+private:
+#   ifdef XMRIG_FEATURE_DMI
+    std::shared_ptr<DmiReader> m_dmi;
+#   endif
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_HWAPI_H */
diff --git a/src/hw/api/api.cmake b/src/hw/api/api.cmake
new file mode 100644
index 000000000..94b224704
--- /dev/null
+++ b/src/hw/api/api.cmake
@@ -0,0 +1,11 @@
+if (WITH_HTTP)
+    add_definitions(/DXMRIG_FEATURE_DMI)
+
+    list(APPEND HEADERS
+        src/hw/api/HwApi.h
+        )
+
+    list(APPEND SOURCES
+        src/hw/api/HwApi.cpp
+        )
+endif()
diff --git a/src/hw/dmi/DmiBoard.cpp b/src/hw/dmi/DmiBoard.cpp
new file mode 100644
index 000000000..3cbe3dd9a
--- /dev/null
+++ b/src/hw/dmi/DmiBoard.cpp
@@ -0,0 +1,50 @@
+/* XMRig
+ * Copyright (c) 2000-2002 Alan Cox     <alan@redhat.com>
+ * Copyright (c) 2005-2020 Jean Delvare <jdelvare@suse.de>
+ * 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 "hw/dmi/DmiBoard.h"
+#include "3rdparty/rapidjson/document.h"
+#include "hw/dmi/DmiTools.h"
+
+
+void xmrig::DmiBoard::decode(dmi_header *h)
+{
+    if (h->length < 0x08) {
+        return;
+    }
+
+    m_vendor  = dmi_string(h, 0x04);
+    m_product = dmi_string(h, 0x05);
+}
+
+
+#ifdef XMRIG_FEATURE_API
+rapidjson::Value xmrig::DmiBoard::toJSON(rapidjson::Document &doc) const
+{
+    using namespace rapidjson;
+
+    auto &allocator = doc.GetAllocator();
+    Value out(kObjectType);
+    out.AddMember("vendor",     m_vendor.toJSON(doc), allocator);
+    out.AddMember("product",    m_product.toJSON(doc), allocator);
+
+    return out;
+}
+#endif
diff --git a/src/hw/dmi/DmiBoard.h b/src/hw/dmi/DmiBoard.h
new file mode 100644
index 000000000..0c64da17c
--- /dev/null
+++ b/src/hw/dmi/DmiBoard.h
@@ -0,0 +1,58 @@
+/* XMRig
+ * Copyright (c) 2000-2002 Alan Cox     <alan@redhat.com>
+ * Copyright (c) 2005-2020 Jean Delvare <jdelvare@suse.de>
+ * 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_DMIBOARD_H
+#define XMRIG_DMIBOARD_H
+
+
+#include "base/tools/String.h"
+
+
+namespace xmrig {
+
+
+struct dmi_header;
+
+
+class DmiBoard
+{
+public:
+    DmiBoard() = default;
+
+    inline const String &product() const    { return m_product; }
+    inline const String &vendor() const     { return m_vendor; }
+    inline bool isValid() const             { return !m_product.isEmpty() && !m_vendor.isEmpty(); }
+
+    void decode(dmi_header *h);
+
+#   ifdef XMRIG_FEATURE_API
+    rapidjson::Value toJSON(rapidjson::Document &doc) const;
+#   endif
+
+private:
+    String m_product;
+    String m_vendor;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_DMIBOARD_H */
diff --git a/src/hw/dmi/DmiMemory.cpp b/src/hw/dmi/DmiMemory.cpp
new file mode 100644
index 000000000..5b36e2bae
--- /dev/null
+++ b/src/hw/dmi/DmiMemory.cpp
@@ -0,0 +1,218 @@
+/* XMRig
+ * Copyright (c) 2000-2002 Alan Cox     <alan@redhat.com>
+ * Copyright (c) 2005-2020 Jean Delvare <jdelvare@suse.de>
+ * 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 "hw/dmi/DmiMemory.h"
+#include "3rdparty/rapidjson/document.h"
+#include "hw/dmi/DmiTools.h"
+
+
+#include <algorithm>
+#include <array>
+
+
+namespace xmrig {
+
+
+static inline uint16_t dmi_memory_device_width(uint16_t code)
+{
+    return (code == 0xFFFF || code == 0) ? 0 : code;
+}
+
+
+static const char *dmi_memory_device_form_factor(uint8_t code)
+{
+    static const std::array<const char *, 0x10> form_factor
+    {
+        "Other",
+        "Unknown",
+        "SIMM",
+        "SIP",
+        "Chip",
+        "DIP",
+        "ZIP",
+        "Proprietary Card",
+        "DIMM",
+        "TSOP",
+        "Row Of Chips",
+        "RIMM",
+        "SODIMM",
+        "SRIMM",
+        "FB-DIMM",
+        "Die"
+    };
+
+    if (code >= 0x01 && code <= form_factor.size()) {
+        return form_factor[code - 0x01];
+    }
+
+    return form_factor[1];
+}
+
+
+static const char *dmi_memory_device_type(uint8_t code)
+{
+    static const std::array<const char *, 0x23> type
+    {
+        "Other", /* 0x01 */
+        "Unknown",
+        "DRAM",
+        "EDRAM",
+        "VRAM",
+        "SRAM",
+        "RAM",
+        "ROM",
+        "Flash",
+        "EEPROM",
+        "FEPROM",
+        "EPROM",
+        "CDRAM",
+        "3DRAM",
+        "SDRAM",
+        "SGRAM",
+        "RDRAM",
+        "DDR",
+        "DDR2",
+        "DDR2 FB-DIMM",
+        "Reserved",
+        "Reserved",
+        "Reserved",
+        "DDR3",
+        "FBD2",
+        "DDR4",
+        "LPDDR",
+        "LPDDR2",
+        "LPDDR3",
+        "LPDDR4",
+        "Logical non-volatile device",
+        "HBM",
+        "HBM2",
+        "DDR5",
+        "LPDDR5"
+    };
+
+    if (code >= 0x01 && code <= type.size()) {
+        return type[code - 0x01];
+    }
+
+    return type[1];
+}
+
+
+static uint64_t dmi_memory_device_speed(uint16_t code1, uint32_t code2)
+{
+    return (code1 == 0xFFFF) ? code2 : code1;
+}
+
+
+} // namespace xmrig
+
+
+
+xmrig::DmiMemory::DmiMemory(dmi_header *h)
+{
+    if (h->length < 0x15) {
+        return;
+    }
+
+    m_totalWidth = dmi_memory_device_width(dmi_get<uint16_t>(h, 0x08));
+    m_width      = dmi_memory_device_width(dmi_get<uint16_t>(h, 0x0A));
+
+    auto size = dmi_get<uint16_t>(h, 0x0C);
+    if (h->length >= 0x20 && size == 0x7FFF) {
+        m_size = (dmi_get<uint32_t>(h, 0x1C) & 0x7FFFFFFFUL) * 1024ULL * 1024ULL;
+    }
+    else if (size) {
+        m_size = (1024ULL * (size & 0x7FFF) * ((size & 0x8000) ? 1 : 1024ULL));
+    }
+
+    m_formFactor = h->data[0x0E];
+    m_slot       = dmi_string(h, 0x10);
+    m_bank       = dmi_string(h, 0x11);
+    m_type       = h->data[0x12];
+
+    if (!m_size || h->length < 0x17) {
+        return;
+    }
+
+    m_speed = dmi_memory_device_speed(dmi_get<uint16_t>(h, 0x15), h->length >= 0x5C ? dmi_get<uint32_t>(h, 0x54) : 0) * 1000000ULL;
+
+    if (h->length < 0x1B) {
+        return;
+    }
+
+    m_vendor  = dmi_string(h, 0x17);
+    m_product = dmi_string(h, 0x1A);
+
+    if (h->length < 0x1C) {
+        return;
+    }
+
+    m_rank = h->data[0x1B] & 0x0F;
+
+    if (h->length < 0x22) {
+        return;
+    }
+
+    m_speed = std::max<uint64_t>(m_speed, dmi_memory_device_speed(dmi_get<uint16_t>(h, 0x20), h->length >= 0x5C ? dmi_get<uint32_t>(h, 0x58) : 0) * 1000000ULL);
+
+    if (h->length < 0x28) {
+        return;
+    }
+
+    m_voltage = dmi_get<uint16_t>(h, 0x26);
+}
+
+
+const char *xmrig::DmiMemory::formFactor() const
+{
+    return dmi_memory_device_form_factor(m_formFactor);
+}
+
+
+const char *xmrig::DmiMemory::type() const
+{
+    return dmi_memory_device_type(m_type);
+}
+
+
+#ifdef XMRIG_FEATURE_API
+rapidjson::Value xmrig::DmiMemory::toJSON(rapidjson::Document &doc) const
+{
+    using namespace rapidjson;
+
+    auto &allocator = doc.GetAllocator();
+    Value out(kObjectType);
+    out.AddMember("slot",           m_slot.toJSON(doc), allocator);
+    out.AddMember("type",           StringRef(type()), allocator);
+    out.AddMember("form_factor",    StringRef(formFactor()), allocator);
+    out.AddMember("size",           m_size, allocator);
+    out.AddMember("speed",          m_speed, allocator);
+    out.AddMember("rank",           m_rank, allocator);
+    out.AddMember("voltage",        m_voltage, allocator);
+    out.AddMember("width",          m_width, allocator);
+    out.AddMember("total_width",    m_totalWidth, allocator);
+    out.AddMember("vendor",         m_vendor.toJSON(doc), allocator);
+    out.AddMember("product",        m_product.toJSON(doc), allocator);
+    out.AddMember("bank",           m_bank.toJSON(doc), allocator);
+
+    return out;
+}
+#endif
diff --git a/src/hw/dmi/DmiMemory.h b/src/hw/dmi/DmiMemory.h
new file mode 100644
index 000000000..badee2cfd
--- /dev/null
+++ b/src/hw/dmi/DmiMemory.h
@@ -0,0 +1,78 @@
+/* XMRig
+ * Copyright (c) 2000-2002 Alan Cox     <alan@redhat.com>
+ * Copyright (c) 2005-2020 Jean Delvare <jdelvare@suse.de>
+ * 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_DMIMEMORY_H
+#define XMRIG_DMIMEMORY_H
+
+
+#include "base/tools/String.h"
+
+
+namespace xmrig {
+
+
+struct dmi_header;
+
+
+class DmiMemory
+{
+public:
+    DmiMemory() = default;
+    DmiMemory(dmi_header *h);
+
+    inline bool isValid() const             { return !m_slot.isEmpty(); }
+    inline const String &bank() const       { return m_bank; }
+    inline const String &product() const    { return m_product; }
+    inline const String &slot() const       { return m_slot; }
+    inline const String &vendor() const     { return m_vendor; }
+    inline uint16_t totalWidth() const      { return m_totalWidth; }
+    inline uint16_t voltage() const         { return m_voltage; }
+    inline uint16_t width() const           { return m_width; }
+    inline uint64_t size() const            { return m_size; }
+    inline uint64_t speed() const           { return m_speed; }
+    inline uint8_t rank() const             { return m_rank; }
+
+    const char *formFactor() const;
+    const char *type() const;
+
+#   ifdef XMRIG_FEATURE_API
+    rapidjson::Value toJSON(rapidjson::Document &doc) const;
+#   endif
+
+private:
+    String m_bank;
+    String m_product;
+    String m_slot;
+    String m_vendor;
+    uint16_t m_totalWidth   = 0;
+    uint16_t m_voltage      = 0;
+    uint16_t m_width        = 0;
+    uint64_t m_size         = 0;
+    uint64_t m_speed        = 0;
+    uint8_t m_formFactor    = 0;
+    uint8_t m_rank          = 0;
+    uint8_t m_type          = 0;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_DMIMEMORY_H */
diff --git a/src/hw/dmi/DmiReader.cpp b/src/hw/dmi/DmiReader.cpp
new file mode 100644
index 000000000..18211759a
--- /dev/null
+++ b/src/hw/dmi/DmiReader.cpp
@@ -0,0 +1,139 @@
+/* XMRig
+ * Copyright (c) 2000-2002 Alan Cox     <alan@redhat.com>
+ * Copyright (c) 2005-2020 Jean Delvare <jdelvare@suse.de>
+ * 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 "hw/dmi/DmiReader.h"
+#include "3rdparty/fmt/core.h"
+#include "3rdparty/rapidjson/document.h"
+#include "hw/dmi/DmiTools.h"
+
+
+namespace xmrig {
+
+
+static void dmi_get_header(dmi_header *h, uint8_t *data)
+{
+    h->type   = data[0];
+    h->length = data[1];
+    h->handle = dmi_get<uint16_t>(data + 2);
+    h->data   = data;
+}
+
+
+} // namespace xmrig
+
+
+#ifdef XMRIG_FEATURE_API
+rapidjson::Value xmrig::DmiReader::toJSON(rapidjson::Document &doc) const
+{
+    rapidjson::Value obj;
+    toJSON(obj, doc);
+
+    return obj;
+}
+
+
+void xmrig::DmiReader::toJSON(rapidjson::Value &out, rapidjson::Document &doc) const
+{
+    using namespace rapidjson;
+
+    auto &allocator = doc.GetAllocator();
+    out.SetObject();
+
+    Value memory(kArrayType);
+    memory.Reserve(m_memory.size(), allocator);
+
+    for (const auto &value : m_memory) {
+        memory.PushBack(value.toJSON(doc), allocator);
+    }
+
+    out.AddMember("smbios",     Value(fmt::format("{}.{}.{}", m_version >> 16, m_version >> 8 & 0xff, m_version & 0xff).c_str(), allocator), allocator);
+    out.AddMember("system",     m_system.toJSON(doc), allocator);
+    out.AddMember("board",      m_board.toJSON(doc), allocator);
+    out.AddMember("memory",     memory, allocator);
+}
+#endif
+
+
+bool xmrig::DmiReader::decode(uint8_t *buf, const Cleanup &cleanup)
+{
+    const bool rc = decode(buf);
+
+    cleanup();
+
+    return rc;
+}
+
+
+bool xmrig::DmiReader::decode(uint8_t *buf)
+{
+    if (!buf) {
+        return false;
+    }
+
+    uint8_t *data = buf;
+    int i         = 0;
+
+    while (data + 4 <= buf + m_size) {
+        dmi_header h{};
+        dmi_get_header(&h, data);
+
+        if (h.length < 4 || h.type == 127) {
+            break;
+        }
+        i++;
+
+        uint8_t *next = data + h.length;
+        while (static_cast<uint32_t>(next - buf + 1) < m_size && (next[0] != 0 || next[1] != 0)) {
+            next++;
+        }
+
+#       ifdef XMRIG_OS_APPLE
+        while ((unsigned long)(next - buf + 1) < m_size && (next[0] == 0 && next[1] == 0))
+#       endif
+        next += 2;
+
+        if (static_cast<uint32_t>(next - buf) > m_size) {
+            data = next;
+            break;
+        }
+
+        switch (h.type) {
+        case 1:
+            m_system.decode(&h);
+            break;
+
+        case 2:
+            m_board.decode(&h);
+            break;
+
+        case 17:
+            m_memory.emplace_back(&h);
+            break;
+
+        default:
+            break;
+        }
+
+        data = next;
+    }
+
+    return true;
+}
diff --git a/src/hw/dmi/DmiReader.h b/src/hw/dmi/DmiReader.h
new file mode 100644
index 000000000..a4f7eb8a7
--- /dev/null
+++ b/src/hw/dmi/DmiReader.h
@@ -0,0 +1,70 @@
+/* XMRig
+ * Copyright (c) 2000-2002 Alan Cox     <alan@redhat.com>
+ * Copyright (c) 2005-2020 Jean Delvare <jdelvare@suse.de>
+ * 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_DMIREADER_H
+#define XMRIG_DMIREADER_H
+
+
+#include "hw/dmi/DmiBoard.h"
+#include "hw/dmi/DmiMemory.h"
+
+
+#include <functional>
+
+
+namespace xmrig {
+
+
+class DmiReader
+{
+public:
+    DmiReader() = default;
+
+    inline const DmiBoard &board() const                { return m_board; }
+    inline const DmiBoard &system() const               { return m_system; }
+    inline const std::vector<DmiMemory> &memory() const { return m_memory; }
+    inline uint32_t size() const                        { return m_size; }
+    inline uint32_t version() const                     { return m_version; }
+
+    bool read();
+
+#   ifdef XMRIG_FEATURE_API
+    rapidjson::Value toJSON(rapidjson::Document &doc) const;
+    void toJSON(rapidjson::Value &out, rapidjson::Document &doc) const;
+#   endif
+
+private:
+    using Cleanup = std::function<void()>;
+
+    bool decode(uint8_t *buf, const Cleanup &cleanup);
+    bool decode(uint8_t *buf);
+
+    DmiBoard m_board;
+    DmiBoard m_system;
+    std::vector<DmiMemory> m_memory;
+    uint32_t m_size     = 0;
+    uint32_t m_version  = 0;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_DMIREADER_H */
diff --git a/src/hw/dmi/DmiReader_mac.cpp b/src/hw/dmi/DmiReader_mac.cpp
new file mode 100644
index 000000000..a23bfe47f
--- /dev/null
+++ b/src/hw/dmi/DmiReader_mac.cpp
@@ -0,0 +1,108 @@
+/* XMRig
+ * Copyright (c) 2002-2006 Hugo Weber  <address@hidden>
+ * 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 "hw/dmi/DmiReader.h"
+#include "hw/dmi/DmiTools.h"
+
+
+#include <Carbon/Carbon.h>
+
+
+namespace xmrig {
+
+
+static int checksum(const uint8_t *buf, size_t len)
+{
+    uint8_t sum = 0;
+
+    for (size_t a = 0; a < len; a++) {
+        sum += buf[a];
+    }
+
+    return (sum == 0);
+}
+
+
+static uint8_t *dmi_table(uint32_t base, uint32_t &len, io_service_t service)
+{
+    CFMutableDictionaryRef properties = nullptr;
+    if (IORegistryEntryCreateCFProperties(service, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) {
+        return nullptr;
+    }
+
+    CFDataRef data;
+    uint8_t *buf = nullptr;
+
+    if (CFDictionaryGetValueIfPresent(properties, CFSTR("SMBIOS"), (const void **)&data)) {
+        assert(len == CFDataGetLength(data));
+
+        len = CFDataGetLength(data);
+        buf = reinterpret_cast<uint8_t *>(malloc(len));
+
+        CFDataGetBytes(data, CFRangeMake(0, len), buf);
+    }
+
+    CFRelease(properties);
+
+    return buf;
+}
+
+
+static uint8_t *smbios_decode(uint8_t *buf, uint32_t &size, uint32_t &version, io_service_t service)
+{
+    if (buf[0x05] > 0x20 || !checksum(buf, buf[0x05]) || memcmp(buf + 0x10, "_DMI_", 5) != 0 || !checksum(buf + 0x10, 0x0F))  {
+        return nullptr;
+    }
+
+    version = ((buf[0x06] << 8) + buf[0x07]) << 8;
+    size    = dmi_get<uint16_t>(buf + 0x16);
+
+    return dmi_table(dmi_get<uint32_t>(buf + 0x18), size, service);
+}
+
+} // namespace xmrig
+
+
+bool xmrig::DmiReader::read()
+{
+    mach_port_t port;
+    IOMasterPort(MACH_PORT_NULL, &port);
+
+    io_service_t service = IOServiceGetMatchingService(port, IOServiceMatching("AppleSMBIOS"));
+    if (service == MACH_PORT_NULL) {
+        return false;
+    }
+
+    CFDataRef data = reinterpret_cast<CFDataRef>(IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS-EPS"), kCFAllocatorDefault, kNilOptions));
+    if (!data) {
+        return false;
+    }
+
+    uint8_t buf[0x20]{};
+    CFDataGetBytes(data, CFRangeMake(0, sizeof(buf)), buf);
+    CFRelease(data);
+
+    auto smb      = smbios_decode(buf, m_size, m_version, service);
+    const bool rc = smb ? decode(smb) : false;
+
+    IOObjectRelease(service);
+
+    return rc;
+}
diff --git a/src/hw/dmi/DmiReader_unix.cpp b/src/hw/dmi/DmiReader_unix.cpp
new file mode 100644
index 000000000..ff57b7a6a
--- /dev/null
+++ b/src/hw/dmi/DmiReader_unix.cpp
@@ -0,0 +1,415 @@
+/* XMRig
+ * Copyright (c) 2000-2002 Alan Cox     <alan@redhat.com>
+ * Copyright (c) 2005-2020 Jean Delvare <jdelvare@suse.de>
+ * 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 "hw/dmi/DmiReader.h"
+#include "hw/dmi/DmiTools.h"
+
+
+#include <cerrno>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#ifdef __FreeBSD__
+#   include <kenv.h>
+#endif
+
+
+#define FLAG_NO_FILE_OFFSET     (1 << 0)
+
+
+namespace xmrig {
+
+
+static const char *kMemDevice       = "/dev/mem";
+static const char *kSysEntryFile    = "/sys/firmware/dmi/tables/smbios_entry_point";
+static const char *kSysTableFile    = "/sys/firmware/dmi/tables/DMI";
+
+
+static inline void safe_memcpy(void *dest, const void *src, size_t n)
+{
+#   ifdef XMRIG_ARM
+    for (size_t i = 0; i < n; i++) {
+        *((uint8_t *)dest + i) = *((const uint8_t *)src + i);
+    }
+#   else
+    memcpy(dest, src, n);
+#   endif
+}
+
+
+
+static int myread(int fd, uint8_t *buf, size_t count, const char *prefix)
+{
+    ssize_t r = 1;
+    size_t r2 = 0;
+
+    while (r2 != count && r != 0) {
+        r = read(fd, buf + r2, count - r2);
+        if (r == -1) {
+            if (errno != EINTR) {
+                return -1;
+            }
+        }
+        else {
+            r2 += r;
+        }
+    }
+
+    if (r2 != count) {
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/*
+ * Reads all of file from given offset, up to max_len bytes.
+ * A buffer of at most max_len bytes is allocated by this function, and
+ * needs to be freed by the caller.
+ * This provides a similar usage model to mem_chunk()
+ *
+ * Returns a pointer to the allocated buffer, or NULL on error, and
+ * sets max_len to the length actually read.
+ */
+static uint8_t *read_file(off_t base, size_t *max_len, const char *filename)
+{
+    const int fd = open(filename, O_RDONLY);
+    uint8_t *p   = nullptr;
+
+    if (fd == -1) {
+        return nullptr;
+    }
+
+    struct stat statbuf{};
+    if (fstat(fd, &statbuf) == 0) {
+        if (base >= statbuf.st_size) {
+            goto out;
+        }
+
+        if (*max_len > static_cast<size_t>(statbuf.st_size) - base) {
+            *max_len = statbuf.st_size - base;
+        }
+    }
+
+    if ((p = reinterpret_cast<uint8_t *>(malloc(*max_len))) == nullptr) {
+        goto out;
+    }
+
+    if (lseek(fd, base, SEEK_SET) == -1) {
+        goto err_free;
+    }
+
+    if (myread(fd, p, *max_len, filename) == 0) {
+        goto out;
+    }
+
+err_free:
+    free(p);
+    p = nullptr;
+
+out:
+    close(fd);
+
+    return p;
+}
+
+
+/*
+ * Copy a physical memory chunk into a memory buffer.
+ * This function allocates memory.
+ */
+static uint8_t *mem_chunk(off_t base, size_t len, const char *devmem)
+{
+    const int fd = open(devmem, O_RDONLY);
+    uint8_t *p   = nullptr;
+    uint8_t *mmp = nullptr;
+    struct stat statbuf{};
+
+#   ifdef _SC_PAGESIZE
+    const off_t mmoffset = base % sysconf(_SC_PAGESIZE);
+#   else
+    const off_t mmoffset = base % getpagesize();
+#   endif
+
+    if (fd == -1) {
+        return nullptr;
+    }
+
+    if ((p = reinterpret_cast<uint8_t *>(malloc(len))) == nullptr) {
+        goto out;
+    }
+
+    if (fstat(fd, &statbuf) == -1) {
+        goto err_free;
+    }
+
+    if (S_ISREG(statbuf.st_mode) && base + (off_t)len > statbuf.st_size) {
+        goto err_free;
+    }
+
+    mmp = reinterpret_cast<uint8_t *>(mmap(nullptr, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset));
+    if (mmp == MAP_FAILED) {
+        goto try_read;
+    }
+
+    safe_memcpy(p, mmp + mmoffset, len);
+    munmap(mmp, mmoffset + len);
+
+    goto out;
+
+try_read:
+    if (lseek(fd, base, SEEK_SET) == -1) {
+        goto err_free;
+    }
+
+    if (myread(fd, p, len, devmem) == 0) {
+        goto out;
+    }
+
+err_free:
+    free(p);
+    p = nullptr;
+
+out:
+    close(fd);
+
+    return p;
+}
+
+
+static int checksum(const uint8_t *buf, size_t len)
+{
+    uint8_t sum = 0;
+
+    for (size_t a = 0; a < len; a++) {
+        sum += buf[a];
+    }
+
+    return (sum == 0);
+}
+
+
+static uint8_t *dmi_table(off_t base, uint32_t &len, const char *devmem, uint32_t flags)
+{
+    if (flags & FLAG_NO_FILE_OFFSET) {
+        size_t size = len;
+        auto buf    = read_file(0, &size, devmem);
+        len         = size;
+
+        return buf;
+    }
+
+    return mem_chunk(base, len, devmem);
+}
+
+
+static uint8_t *smbios3_decode(uint8_t *buf, const char *devmem, uint32_t &size, uint32_t &version, uint32_t flags)
+{
+    if (buf[0x06] > 0x20 || !checksum(buf, buf[0x06])) {
+        return nullptr;
+    }
+
+    version          = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09];
+    size             = dmi_get<uint32_t>(buf + 0x0C);
+    const u64 offset = dmi_get<u64>(buf + 0x10);
+
+    return dmi_table(((off_t)offset.h << 32) | offset.l, size, devmem, flags);
+}
+
+
+static uint8_t *smbios_decode(uint8_t *buf, const char *devmem, uint32_t &size, uint32_t &version, uint32_t flags)
+{
+    if (buf[0x05] > 0x20 || !checksum(buf, buf[0x05]) || memcmp(buf + 0x10, "_DMI_", 5) != 0 || !checksum(buf + 0x10, 0x0F))  {
+        return nullptr;
+    }
+
+    version = (buf[0x06] << 8) + buf[0x07];
+
+    switch (version) {
+    case 0x021F:
+    case 0x0221:
+        version = 0x0203;
+        break;
+
+    case 0x0233:
+        version = 0x0206;
+        break;
+    }
+
+    version = version << 8;
+    size    = dmi_get<uint16_t>(buf + 0x16);
+
+    return dmi_table(dmi_get<uint32_t>(buf + 0x18), size, devmem, flags);
+}
+
+
+static uint8_t *legacy_decode(uint8_t *buf, const char *devmem, uint32_t &size, uint32_t &version, uint32_t flags)
+{
+    if (!checksum(buf, 0x0F)) {
+        return nullptr;
+    }
+
+    version = ((buf[0x0E] & 0xF0) << 12) + ((buf[0x0E] & 0x0F) << 8);
+    size    = dmi_get<uint16_t>(buf + 0x06);
+
+    return dmi_table(dmi_get<uint32_t>(buf + 0x08), size, devmem, flags);
+}
+
+
+#define EFI_NOT_FOUND   (-1)
+#define EFI_NO_SMBIOS   (-2)
+static off_t address_from_efi()
+{
+#   if defined(__linux__)
+    FILE *efi_systab;
+    const char *filename;
+    char linebuf[64];
+    off_t address = 0;
+#   elif defined(__FreeBSD__)
+    char addrstr[KENV_MVALLEN + 1];
+#   endif
+
+#   if defined(__linux__)
+    if ((efi_systab = fopen(filename = "/sys/firmware/efi/systab", "r")) == nullptr && (efi_systab = fopen(filename = "/proc/efi/systab", "r")) == nullptr) {
+        return EFI_NOT_FOUND;
+    }
+
+    address = EFI_NO_SMBIOS;
+    while ((fgets(linebuf, sizeof(linebuf) - 1, efi_systab)) != nullptr) {
+        char *addrp = strchr(linebuf, '=');
+        *(addrp++) = '\0';
+        if (strcmp(linebuf, "SMBIOS3") == 0 || strcmp(linebuf, "SMBIOS") == 0) {
+            address = strtoull(addrp, nullptr, 0);
+            break;
+        }
+    }
+
+    fclose(efi_systab);
+
+    return address;
+#   elif defined(__FreeBSD__)
+    if (kenv(KENV_GET, "hint.smbios.0.mem", addrstr, sizeof(addrstr)) == -1) {
+        return EFI_NOT_FOUND;
+    }
+
+    return strtoull(addrstr, nullptr, 0);
+#   endif
+
+    return EFI_NOT_FOUND;
+}
+
+
+} // namespace xmrig
+
+
+bool xmrig::DmiReader::read()
+{
+    size_t size  = 0x20;
+    uint8_t *buf = read_file(0, &size, kSysEntryFile);
+    uint8_t *smb = nullptr;
+
+    if (buf) {
+        smb = nullptr;
+
+        if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0) {
+            smb = smbios3_decode(buf, kSysTableFile, m_size, m_version, FLAG_NO_FILE_OFFSET);
+        }
+        else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0) {
+            smb = smbios_decode(buf, kSysTableFile, m_size, m_version, FLAG_NO_FILE_OFFSET);
+        }
+        else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0) {
+            smb = legacy_decode(buf, kSysTableFile, m_size, m_version, FLAG_NO_FILE_OFFSET);
+        }
+
+        if (smb) {
+            return decode(smb, [smb, buf]() { free(smb); free(buf); });
+        }
+
+        free(buf);
+    }
+
+    const auto efi = address_from_efi();
+    if (efi == EFI_NO_SMBIOS) {
+        return false;
+    }
+
+    if (efi != EFI_NOT_FOUND) {
+        if ((buf = mem_chunk(efi, 0x20, kMemDevice)) == nullptr) {
+            return false;
+        }
+
+        smb = nullptr;
+
+        if (memcmp(buf, "_SM3_", 5) == 0) {
+            smb = smbios3_decode(buf, kMemDevice, m_size, m_version, 0);
+        }
+        else if (memcmp(buf, "_SM_", 4) == 0) {
+            smb = smbios_decode(buf, kSysTableFile, m_size, m_version, 0);
+        }
+
+        if (smb) {
+            return decode(smb, [smb, buf]() { free(smb); free(buf); });
+        }
+
+        free(buf);
+    }
+
+#   if defined(__x86_64__) || defined(_M_AMD64)
+    if ((buf = mem_chunk(0xF0000, 0x10000, kMemDevice)) == nullptr) {
+        return false;
+    }
+
+    smb = nullptr;
+
+    for (off_t fp = 0; fp <= 0xFFE0; fp += 16) {
+        if (memcmp(buf + fp, "_SM3_", 5) == 0) {
+            smb = smbios3_decode(buf + fp, kMemDevice, m_size, m_version, 0);
+        }
+
+        if (smb) {
+            return decode(smb, [smb, buf]() { free(smb); free(buf); });
+        }
+    }
+
+    for (off_t fp = 0; fp <= 0xFFF0; fp += 16) {
+        if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) {
+            smb = smbios3_decode(buf + fp, kMemDevice, m_size, m_version, 0);
+        }
+        else if (!smb && memcmp(buf + fp, "_DMI_", 5) == 0) {
+            smb = legacy_decode(buf + fp, kMemDevice, m_size, m_version, 0);
+        }
+
+        if (smb) {
+            return decode(smb, [smb, buf]() { free(smb); free(buf); });
+        }
+    }
+
+    free(buf);
+#   endif
+
+
+    return false;
+}
diff --git a/src/hw/dmi/DmiReader_win.cpp b/src/hw/dmi/DmiReader_win.cpp
new file mode 100644
index 000000000..837bdb7b3
--- /dev/null
+++ b/src/hw/dmi/DmiReader_win.cpp
@@ -0,0 +1,68 @@
+/* XMRig
+ * Copyright (c) 2002-2006 Hugo Weber  <address@hidden>
+ * 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 "hw/dmi/DmiReader.h"
+#include "hw/dmi/DmiTools.h"
+
+
+#include <windows.h>
+
+
+namespace xmrig {
+
+
+/*
+ * Struct needed to get the SMBIOS table using GetSystemFirmwareTable API.
+ */
+struct RawSMBIOSData {
+    uint8_t	Used20CallingMethod;
+    uint8_t	SMBIOSMajorVersion;
+    uint8_t	SMBIOSMinorVersion;
+    uint8_t	DmiRevision;
+    uint32_t Length;
+    uint8_t	SMBIOSTableData[];
+};
+
+
+} // namespace xmrig
+
+
+bool xmrig::DmiReader::read()
+{
+    const uint32_t size = GetSystemFirmwareTable('RSMB', 0, nullptr, 0);
+    auto smb            = reinterpret_cast<RawSMBIOSData *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size));
+
+    if (!smb) {
+        return false;
+    }
+
+    if (GetSystemFirmwareTable('RSMB', 0, smb, size) != size) {
+        HeapFree(GetProcessHeap(), 0, smb);
+
+        return false;
+    }
+
+    m_version = (smb->SMBIOSMajorVersion << 16) + (smb->SMBIOSMinorVersion << 8) + smb->DmiRevision;
+    m_size    = smb->Length;
+
+    return decode(smb->SMBIOSTableData, [smb]() {
+        HeapFree(GetProcessHeap(), 0, smb);
+    });
+}
diff --git a/src/hw/dmi/DmiTools.cpp b/src/hw/dmi/DmiTools.cpp
new file mode 100644
index 000000000..e82c2f452
--- /dev/null
+++ b/src/hw/dmi/DmiTools.cpp
@@ -0,0 +1,75 @@
+/* XMRig
+ * Copyright (c) 2000-2002 Alan Cox     <alan@redhat.com>
+ * Copyright (c) 2005-2020 Jean Delvare <jdelvare@suse.de>
+ * 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 "hw/dmi/DmiTools.h"
+
+
+#include <cstring>
+
+
+namespace xmrig {
+
+
+/* Replace non-ASCII characters with dots */
+static void ascii_filter(char *bp, size_t len)
+{
+    for (size_t i = 0; i < len; i++) {
+        if (bp[i] < 32 || bp[i] >= 127) {
+            bp[i] = '.';
+        }
+    }
+}
+
+
+static char *_dmi_string(dmi_header *dm, uint8_t s, bool filter)
+{
+    char *bp = reinterpret_cast<char *>(dm->data);
+
+    bp += dm->length;
+    while (s > 1 && *bp)  {
+        bp += strlen(bp);
+        bp++;
+        s--;
+    }
+
+    if (!*bp) {
+        return nullptr;
+    }
+
+    if (filter) {
+        ascii_filter(bp, strlen(bp));
+    }
+
+    return bp;
+}
+
+
+const char *dmi_string(dmi_header *dm, size_t offset)
+{
+    if (offset < 4) {
+        return nullptr;
+    }
+
+    return _dmi_string(dm, dm->data[offset], true);
+}
+
+
+} // namespace xmrig
diff --git a/src/hw/dmi/DmiTools.h b/src/hw/dmi/DmiTools.h
new file mode 100644
index 000000000..65a1dfd75
--- /dev/null
+++ b/src/hw/dmi/DmiTools.h
@@ -0,0 +1,60 @@
+/* XMRig
+ * Copyright (c) 2000-2002 Alan Cox     <alan@redhat.com>
+ * Copyright (c) 2005-2020 Jean Delvare <jdelvare@suse.de>
+ * 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_DMITOOLS_H
+#define XMRIG_DMITOOLS_H
+
+
+#include <cstddef>
+#include <cstdint>
+
+
+namespace xmrig {
+
+
+struct dmi_header
+{
+    uint8_t type;
+    uint8_t length;
+    uint16_t handle;
+    uint8_t *data;
+};
+
+
+struct u64 {
+    uint32_t l;
+    uint32_t h;
+};
+
+
+template<typename T>
+inline T dmi_get(const uint8_t *data)                   { return *reinterpret_cast<const T *>(data); }
+
+template<typename T>
+inline T dmi_get(const dmi_header *h, size_t offset)    { return *reinterpret_cast<const T *>(h->data + offset); }
+
+
+const char *dmi_string(dmi_header *dm, size_t offset);
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_DMITOOLS_H */
diff --git a/src/hw/dmi/dmi.cmake b/src/hw/dmi/dmi.cmake
new file mode 100644
index 000000000..5140692a7
--- /dev/null
+++ b/src/hw/dmi/dmi.cmake
@@ -0,0 +1,33 @@
+if (WITH_DMI)
+    set(WITH_DMI XMRIG_OS_WIN OR XMRIG_OS_LINUX OR XMRIG_OS_FREEBSD OR (XMRIG_OS_MACOS AND NOT XMRIG_ARM))
+endif()
+
+if (WITH_DMI)
+    add_definitions(/DXMRIG_FEATURE_DMI)
+
+    list(APPEND HEADERS
+        src/hw/dmi/DmiBoard.h
+        src/hw/dmi/DmiMemory.h
+        src/hw/dmi/DmiReader.h
+        src/hw/dmi/DmiTools.h
+        )
+
+    list(APPEND SOURCES
+        src/hw/dmi/DmiBoard.cpp
+        src/hw/dmi/DmiMemory.cpp
+        src/hw/dmi/DmiReader.cpp
+        src/hw/dmi/DmiTools.cpp
+        )
+
+    if (XMRIG_OS_WIN)
+        list(APPEND SOURCES src/hw/dmi/DmiReader_win.cpp)
+    elseif(XMRIG_OS_LINUX OR XMRIG_OS_FREEBSD)
+        list(APPEND SOURCES src/hw/dmi/DmiReader_unix.cpp)
+    elseif(XMRIG_OS_MACOS)
+        list(APPEND SOURCES src/hw/dmi/DmiReader_mac.cpp)
+        find_library(CORESERVICES_LIBRARY CoreServices)
+        list(APPEND EXTRA_LIBS ${CORESERVICES_LIBRARY})
+    endif()
+else()
+    remove_definitions(/DXMRIG_FEATURE_DMI)
+endif()