From 11e0d3de3aa501dcd44172b17f4b64ecced9607d Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Mon, 18 Jan 2021 11:23:29 +0700
Subject: [PATCH 01/11] Added DMI reader (Windows only).

---
 CMakeLists.txt                |   3 +
 src/Summary.cpp               |  30 ++++++
 src/hw/dmi/DmiBoard.cpp       |  35 +++++++
 src/hw/dmi/DmiBoard.h         |  54 ++++++++++
 src/hw/dmi/DmiMemory.cpp      | 192 ++++++++++++++++++++++++++++++++++
 src/hw/dmi/DmiMemory.h        |  74 +++++++++++++
 src/hw/dmi/DmiReader.cpp      |  87 +++++++++++++++
 src/hw/dmi/DmiReader.h        |  59 +++++++++++
 src/hw/dmi/DmiReader_unix.cpp |  26 +++++
 src/hw/dmi/DmiReader_win.cpp  | 112 ++++++++++++++++++++
 src/hw/dmi/DmiTools.cpp       |  75 +++++++++++++
 src/hw/dmi/DmiTools.h         |  53 ++++++++++
 src/hw/dmi/dmi.cmake          |  25 +++++
 13 files changed, 825 insertions(+)
 create mode 100644 src/hw/dmi/DmiBoard.cpp
 create mode 100644 src/hw/dmi/DmiBoard.h
 create mode 100644 src/hw/dmi/DmiMemory.cpp
 create mode 100644 src/hw/dmi/DmiMemory.h
 create mode 100644 src/hw/dmi/DmiReader.cpp
 create mode 100644 src/hw/dmi/DmiReader.h
 create mode 100644 src/hw/dmi/DmiReader_unix.cpp
 create mode 100644 src/hw/dmi/DmiReader_win.cpp
 create mode 100644 src/hw/dmi/DmiTools.cpp
 create mode 100644 src/hw/dmi/DmiTools.h
 create mode 100644 src/hw/dmi/dmi.cmake

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 35fba8ea5..c1a222fc4 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 reader" OFF)
 
 option(BUILD_STATIC         "Build static binary" OFF)
 option(ARM_TARGET           "Force use specific ARM target 8 or 7" 0)
@@ -197,6 +198,8 @@ if (WITH_EMBEDDED_CONFIG)
     add_definitions(/DXMRIG_FEATURE_EMBEDDED_CONFIG)
 endif()
 
+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..345ed48e7 100644
--- a/src/Summary.cpp
+++ b/src/Summary.cpp
@@ -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
@@ -130,6 +135,31 @@ static void print_memory()
                totalMem / oneGiB,
                percent
                );
+
+#   ifdef XMRIG_FEATURE_DMI
+    DmiReader reader;
+    if (!reader.read()) {
+        return;
+    }
+
+    for (const auto &memory : reader.memory()) {
+        if (!memory.isValid()) {
+            continue;
+        }
+
+        if (!memory.size()) {
+            Log::print(WHITE_BOLD("   %-13s") WHITE_BOLD("%s: ") BLACK_BOLD("<empty>"), "", memory.slot().data());
+            continue;
+        }
+
+        Log::print(WHITE_BOLD("   %-13s") WHITE_BOLD("%s: ") CYAN_BOLD("%" PRIu64 " GB ") WHITE_BOLD("%s @ %" PRIu64 " MHz ") BLACK_BOLD("%s"),
+                   "", memory.slot().data(), memory.size() / oneGiB, memory.type(), memory.speed() / 1000000ULL, memory.product().data());
+    }
+
+    if (reader.board().isValid()) {
+        Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s") " - " WHITE_BOLD("%s"), "MOTHERBOARD", reader.board().vendor().data(), reader.board().product().data());
+    }
+#   endif
 }
 
 
diff --git a/src/hw/dmi/DmiBoard.cpp b/src/hw/dmi/DmiBoard.cpp
new file mode 100644
index 000000000..381865f4e
--- /dev/null
+++ b/src/hw/dmi/DmiBoard.cpp
@@ -0,0 +1,35 @@
+/* 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 "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);
+}
diff --git a/src/hw/dmi/DmiBoard.h b/src/hw/dmi/DmiBoard.h
new file mode 100644
index 000000000..dd28a607b
--- /dev/null
+++ b/src/hw/dmi/DmiBoard.h
@@ -0,0 +1,54 @@
+/* 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);
+
+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..0006d0063
--- /dev/null
+++ b/src/hw/dmi/DmiMemory.cpp
@@ -0,0 +1,192 @@
+/* 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 "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(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);
+}
diff --git a/src/hw/dmi/DmiMemory.h b/src/hw/dmi/DmiMemory.h
new file mode 100644
index 000000000..b9a0468b0
--- /dev/null
+++ b/src/hw/dmi/DmiMemory.h
@@ -0,0 +1,74 @@
+/* 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;
+
+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..660838454
--- /dev/null
+++ b/src/hw/dmi/DmiReader.cpp
@@ -0,0 +1,87 @@
+/* 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"
+
+
+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
+
+
+bool xmrig::DmiReader::decode(uint8_t *buf)
+{
+    if (!buf || !m_count) {
+        return false;
+    }
+
+    uint8_t *data = buf;
+    int i         = 0;
+
+    while ((i < m_count || !m_count) && 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++;
+        }
+        next += 2;
+
+        if (static_cast<uint32_t>(next - buf) > m_size) {
+            data = next;
+            break;
+        }
+
+        switch (h.type) {
+        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..69ba483b9
--- /dev/null
+++ b/src/hw/dmi/DmiReader.h
@@ -0,0 +1,59 @@
+/* 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"
+
+
+namespace xmrig {
+
+
+class DmiReader
+{
+public:
+    DmiReader() = default;
+
+    inline const DmiBoard &board() const                { return m_board; }
+    inline const std::vector<DmiMemory> &memory() const { return m_memory; }
+    inline uint16_t count() const                       { return m_count; }
+    inline uint32_t size() const                        { return m_size; }
+    inline uint32_t version() const                     { return m_version; }
+
+    bool read();
+
+private:
+    bool decode(uint8_t *buf);
+
+    DmiBoard m_board;
+    uint16_t m_count    = 0;
+    uint32_t m_size     = 0;
+    uint32_t m_version  = 0;
+    std::vector<DmiMemory> m_memory;
+};
+
+
+} /* namespace xmrig */
+
+
+#endif /* XMRIG_DMIREADER_H */
diff --git a/src/hw/dmi/DmiReader_unix.cpp b/src/hw/dmi/DmiReader_unix.cpp
new file mode 100644
index 000000000..4919935fd
--- /dev/null
+++ b/src/hw/dmi/DmiReader_unix.cpp
@@ -0,0 +1,26 @@
+/* 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/dmi/DmiReader.h"
+
+
+bool xmrig::DmiReader::read()
+{
+    return false;
+}
diff --git a/src/hw/dmi/DmiReader_win.cpp b/src/hw/dmi/DmiReader_win.cpp
new file mode 100644
index 000000000..6b8e2ac46
--- /dev/null
+++ b/src/hw/dmi/DmiReader_win.cpp
@@ -0,0 +1,112 @@
+/* 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[];
+};
+
+
+/*
+ * Counts the number of SMBIOS structures present in
+ * the SMBIOS table.
+ *
+ * buf - Pointer that receives the SMBIOS Table address.
+ *       This will be the address of the BYTE array from
+ *       the RawSMBIOSData struct.
+ *
+ * len - The length of the SMBIOS Table pointed by buff.
+ *
+ * return - The number of SMBIOS strutctures.
+ *
+ * Remarks:
+ * The SMBIOS Table Entry Point has this information,
+ * however the GetSystemFirmwareTable API doesn't
+ * return all fields from the Entry Point, and
+ * DMIDECODE uses this value as a parameter for
+ * dmi_table function. This is the reason why
+ * this function was make.
+ *
+ * Hugo Weber address@hidden
+ */
+uint16_t count_smbios_structures(const uint8_t *buf, uint32_t len)
+{
+    uint16_t count  = 0;
+    uint32_t offset = 0;
+
+    while (offset < len) {
+        offset += reinterpret_cast<const dmi_header *>(buf + offset)->length;
+        count++;
+
+        while ((*reinterpret_cast<const uint16_t *>(buf + offset) != 0) && (offset < len)) {
+            offset++;
+        }
+
+        offset += 2;
+    }
+
+    return count;
+}
+
+
+} // 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;
+    m_count   = count_smbios_structures(smb->SMBIOSTableData, m_size);
+
+    const bool rc = decode(smb->SMBIOSTableData);
+    HeapFree(GetProcessHeap(), 0, smb);
+
+    return rc;
+}
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..e929e6fe5
--- /dev/null
+++ b/src/hw/dmi/DmiTools.h
@@ -0,0 +1,53 @@
+/* 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 <cstdint>
+
+
+namespace xmrig {
+
+
+struct dmi_header
+{
+    uint8_t type;
+    uint8_t length;
+    uint16_t handle;
+    uint8_t *data;
+};
+
+
+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..ff4882ce0
--- /dev/null
+++ b/src/hw/dmi/dmi.cmake
@@ -0,0 +1,25 @@
+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)
+        list(APPEND SOURCES src/hw/dmi/DmiReader_unix.cpp)
+    endif()
+else()
+    remove_definitions(/DXMRIG_FEATURE_DMI)
+endif()

From 05e6f661690f067b2ed0f507ea8717b73449e7ed Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Mon, 18 Jan 2021 16:53:42 +0700
Subject: [PATCH 02/11] Added basic Linux support.

---
 CMakeLists.txt                |   2 +-
 src/hw/dmi/DmiMemory.cpp      |   2 +-
 src/hw/dmi/DmiReader.cpp      |   4 +-
 src/hw/dmi/DmiReader.h        |   2 -
 src/hw/dmi/DmiReader_unix.cpp | 168 +++++++++++++++++++++++++++++++++-
 src/hw/dmi/DmiReader_win.cpp  |  43 ---------
 src/hw/dmi/DmiTools.h         |   7 ++
 7 files changed, 177 insertions(+), 51 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c1a222fc4..69f40fcdd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -170,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)
 
diff --git a/src/hw/dmi/DmiMemory.cpp b/src/hw/dmi/DmiMemory.cpp
index 0006d0063..f02a64ecd 100644
--- a/src/hw/dmi/DmiMemory.cpp
+++ b/src/hw/dmi/DmiMemory.cpp
@@ -170,7 +170,7 @@ xmrig::DmiMemory::DmiMemory(dmi_header *h)
         return;
     }
 
-    m_speed = std::max(m_speed, dmi_memory_device_speed(dmi_get<uint16_t>(h, 0x20), h->length >= 0x5C ? dmi_get<uint32_t>(h, 0x58) : 0) * 1000000ULL);
+    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;
diff --git a/src/hw/dmi/DmiReader.cpp b/src/hw/dmi/DmiReader.cpp
index 660838454..66f1dd5fa 100644
--- a/src/hw/dmi/DmiReader.cpp
+++ b/src/hw/dmi/DmiReader.cpp
@@ -40,14 +40,14 @@ static void dmi_get_header(dmi_header *h, uint8_t *data)
 
 bool xmrig::DmiReader::decode(uint8_t *buf)
 {
-    if (!buf || !m_count) {
+    if (!buf) {
         return false;
     }
 
     uint8_t *data = buf;
     int i         = 0;
 
-    while ((i < m_count || !m_count) && data + 4 <= buf + m_size) {
+    while (data + 4 <= buf + m_size) {
         dmi_header h{};
         dmi_get_header(&h, data);
 
diff --git a/src/hw/dmi/DmiReader.h b/src/hw/dmi/DmiReader.h
index 69ba483b9..243b5164b 100644
--- a/src/hw/dmi/DmiReader.h
+++ b/src/hw/dmi/DmiReader.h
@@ -36,7 +36,6 @@ public:
 
     inline const DmiBoard &board() const                { return m_board; }
     inline const std::vector<DmiMemory> &memory() const { return m_memory; }
-    inline uint16_t count() const                       { return m_count; }
     inline uint32_t size() const                        { return m_size; }
     inline uint32_t version() const                     { return m_version; }
 
@@ -46,7 +45,6 @@ private:
     bool decode(uint8_t *buf);
 
     DmiBoard m_board;
-    uint16_t m_count    = 0;
     uint32_t m_size     = 0;
     uint32_t m_version  = 0;
     std::vector<DmiMemory> m_memory;
diff --git a/src/hw/dmi/DmiReader_unix.cpp b/src/hw/dmi/DmiReader_unix.cpp
index 4919935fd..e9b25abcb 100644
--- a/src/hw/dmi/DmiReader_unix.cpp
+++ b/src/hw/dmi/DmiReader_unix.cpp
@@ -1,6 +1,8 @@
 /* XMRig
- * Copyright (c) 2018-2021 SChernykh   <https://github.com/SChernykh>
- * Copyright (c) 2016-2021 XMRig       <https://github.com/xmrig>, <support@xmrig.com>
+ * 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
@@ -18,9 +20,171 @@
 
 
 #include "hw/dmi/DmiReader.h"
+#include "hw/dmi/DmiTools.h"
+
+
+#include <cerrno>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#define FLAG_NO_FILE_OFFSET     (1 << 0)
+
+
+namespace xmrig {
+
+
+static const char *kSysEntryFile = "/sys/firmware/dmi/tables/smbios_entry_point";
+static const char *kSysTableFile = "/sys/firmware/dmi/tables/DMI";
+
+
+
+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;
+}
+
+
+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)
+{
+    uint8_t *buf = nullptr;
+
+    if (flags & FLAG_NO_FILE_OFFSET) {
+        size_t size = len;
+        buf         = read_file(0, &size, devmem);
+        len         = size;
+    }
+    else {
+        // FIXME
+    }
+
+    return buf;
+}
+
+
+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);;
+}
+
+
+} // namespace xmrig
 
 
 bool xmrig::DmiReader::read()
 {
+    size_t size  = 0x20;
+    uint8_t *buf = read_file(0, &size, kSysEntryFile);
+
+    if (buf) {
+        uint8_t *smb = nullptr;
+
+        if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0) {
+            smb = smbios3_decode(buf, kSysTableFile, m_size, m_version, FLAG_NO_FILE_OFFSET);
+        }
+
+        if (smb) {
+            decode(smb);
+
+            free(smb);
+            free(buf);
+
+            return true;
+        }
+    }
+
     return false;
 }
diff --git a/src/hw/dmi/DmiReader_win.cpp b/src/hw/dmi/DmiReader_win.cpp
index 6b8e2ac46..b79f952a4 100644
--- a/src/hw/dmi/DmiReader_win.cpp
+++ b/src/hw/dmi/DmiReader_win.cpp
@@ -41,48 +41,6 @@ struct RawSMBIOSData {
 };
 
 
-/*
- * Counts the number of SMBIOS structures present in
- * the SMBIOS table.
- *
- * buf - Pointer that receives the SMBIOS Table address.
- *       This will be the address of the BYTE array from
- *       the RawSMBIOSData struct.
- *
- * len - The length of the SMBIOS Table pointed by buff.
- *
- * return - The number of SMBIOS strutctures.
- *
- * Remarks:
- * The SMBIOS Table Entry Point has this information,
- * however the GetSystemFirmwareTable API doesn't
- * return all fields from the Entry Point, and
- * DMIDECODE uses this value as a parameter for
- * dmi_table function. This is the reason why
- * this function was make.
- *
- * Hugo Weber address@hidden
- */
-uint16_t count_smbios_structures(const uint8_t *buf, uint32_t len)
-{
-    uint16_t count  = 0;
-    uint32_t offset = 0;
-
-    while (offset < len) {
-        offset += reinterpret_cast<const dmi_header *>(buf + offset)->length;
-        count++;
-
-        while ((*reinterpret_cast<const uint16_t *>(buf + offset) != 0) && (offset < len)) {
-            offset++;
-        }
-
-        offset += 2;
-    }
-
-    return count;
-}
-
-
 } // namespace xmrig
 
 
@@ -103,7 +61,6 @@ bool xmrig::DmiReader::read()
 
     m_version = (smb->SMBIOSMajorVersion << 16) + (smb->SMBIOSMinorVersion << 8) + smb->DmiRevision;
     m_size    = smb->Length;
-    m_count   = count_smbios_structures(smb->SMBIOSTableData, m_size);
 
     const bool rc = decode(smb->SMBIOSTableData);
     HeapFree(GetProcessHeap(), 0, smb);
diff --git a/src/hw/dmi/DmiTools.h b/src/hw/dmi/DmiTools.h
index e929e6fe5..65a1dfd75 100644
--- a/src/hw/dmi/DmiTools.h
+++ b/src/hw/dmi/DmiTools.h
@@ -22,6 +22,7 @@
 #define XMRIG_DMITOOLS_H
 
 
+#include <cstddef>
 #include <cstdint>
 
 
@@ -37,6 +38,12 @@ struct dmi_header
 };
 
 
+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); }
 

From 3b8d081c8c63c717dc366f17fad861b75cea45c7 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Mon, 18 Jan 2021 22:56:57 +0700
Subject: [PATCH 03/11] Add support for older DMI formats on Linux.

---
 src/Summary.cpp               |  6 ++--
 src/hw/dmi/DmiReader.cpp      | 10 ++++++
 src/hw/dmi/DmiReader.h        |  6 ++++
 src/hw/dmi/DmiReader_unix.cpp | 57 ++++++++++++++++++++++++++++++-----
 src/hw/dmi/DmiReader_win.cpp  |  7 ++---
 5 files changed, 72 insertions(+), 14 deletions(-)

diff --git a/src/Summary.cpp b/src/Summary.cpp
index 345ed48e7..b925232fd 100644
--- a/src/Summary.cpp
+++ b/src/Summary.cpp
@@ -129,7 +129,7 @@ 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,
@@ -148,11 +148,11 @@ static void print_memory()
         }
 
         if (!memory.size()) {
-            Log::print(WHITE_BOLD("   %-13s") WHITE_BOLD("%s: ") BLACK_BOLD("<empty>"), "", memory.slot().data());
+            Log::print(WHITE_BOLD("   %-13s") "%s: " BLACK_BOLD("<empty>"), "", memory.slot().data());
             continue;
         }
 
-        Log::print(WHITE_BOLD("   %-13s") WHITE_BOLD("%s: ") CYAN_BOLD("%" PRIu64 " GB ") WHITE_BOLD("%s @ %" PRIu64 " MHz ") BLACK_BOLD("%s"),
+        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());
     }
 
diff --git a/src/hw/dmi/DmiReader.cpp b/src/hw/dmi/DmiReader.cpp
index 66f1dd5fa..8993531a6 100644
--- a/src/hw/dmi/DmiReader.cpp
+++ b/src/hw/dmi/DmiReader.cpp
@@ -38,6 +38,16 @@ static void dmi_get_header(dmi_header *h, uint8_t *data)
 } // namespace xmrig
 
 
+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) {
diff --git a/src/hw/dmi/DmiReader.h b/src/hw/dmi/DmiReader.h
index 243b5164b..f140f8676 100644
--- a/src/hw/dmi/DmiReader.h
+++ b/src/hw/dmi/DmiReader.h
@@ -26,6 +26,9 @@
 #include "hw/dmi/DmiMemory.h"
 
 
+#include <functional>
+
+
 namespace xmrig {
 
 
@@ -42,6 +45,9 @@ public:
     bool read();
 
 private:
+    using Cleanup = std::function<void()>;
+
+    bool decode(uint8_t *buf, const Cleanup &cleanup);
     bool decode(uint8_t *buf);
 
     DmiBoard m_board;
diff --git a/src/hw/dmi/DmiReader_unix.cpp b/src/hw/dmi/DmiReader_unix.cpp
index e9b25abcb..db5160126 100644
--- a/src/hw/dmi/DmiReader_unix.cpp
+++ b/src/hw/dmi/DmiReader_unix.cpp
@@ -157,7 +157,46 @@ static uint8_t *smbios3_decode(uint8_t *buf, const char *devmem, uint32_t &size,
     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);;
+    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);
 }
 
 
@@ -175,14 +214,18 @@ bool xmrig::DmiReader::read()
         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) {
-            decode(smb);
-
-            free(smb);
-            free(buf);
-
-            return true;
+            return decode(smb, [smb, buf]() {
+                free(smb);
+                free(buf);
+            });
         }
     }
 
diff --git a/src/hw/dmi/DmiReader_win.cpp b/src/hw/dmi/DmiReader_win.cpp
index b79f952a4..837bdb7b3 100644
--- a/src/hw/dmi/DmiReader_win.cpp
+++ b/src/hw/dmi/DmiReader_win.cpp
@@ -62,8 +62,7 @@ bool xmrig::DmiReader::read()
     m_version = (smb->SMBIOSMajorVersion << 16) + (smb->SMBIOSMinorVersion << 8) + smb->DmiRevision;
     m_size    = smb->Length;
 
-    const bool rc = decode(smb->SMBIOSTableData);
-    HeapFree(GetProcessHeap(), 0, smb);
-
-    return rc;
+    return decode(smb->SMBIOSTableData, [smb]() {
+        HeapFree(GetProcessHeap(), 0, smb);
+    });
 }

From 3df47052ed499a24d9045efed07a9c5f8713c387 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Tue, 19 Jan 2021 01:23:09 +0700
Subject: [PATCH 04/11] Added legacy DMI readers for Linux.

---
 src/hw/dmi/DmiReader_unix.cpp | 211 +++++++++++++++++++++++++++++++---
 1 file changed, 197 insertions(+), 14 deletions(-)

diff --git a/src/hw/dmi/DmiReader_unix.cpp b/src/hw/dmi/DmiReader_unix.cpp
index db5160126..d73e39436 100644
--- a/src/hw/dmi/DmiReader_unix.cpp
+++ b/src/hw/dmi/DmiReader_unix.cpp
@@ -25,19 +25,38 @@
 
 #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 *kSysEntryFile = "/sys/firmware/dmi/tables/smbios_entry_point";
-static const char *kSysTableFile = "/sys/firmware/dmi/tables/DMI";
+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
+}
 
 
 
@@ -118,6 +137,69 @@ out:
 }
 
 
+/*
+ * 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;
@@ -132,18 +214,15 @@ static int checksum(const uint8_t *buf, size_t len)
 
 static uint8_t *dmi_table(off_t base, uint32_t &len, const char *devmem, uint32_t flags)
 {
-    uint8_t *buf = nullptr;
-
     if (flags & FLAG_NO_FILE_OFFSET) {
         size_t size = len;
-        buf         = read_file(0, &size, devmem);
+        auto buf    = read_file(0, &size, devmem);
         len         = size;
-    }
-    else {
-        // FIXME
+
+        return buf;
     }
 
-    return buf;
+    return mem_chunk(base, len, devmem);
 }
 
 
@@ -200,6 +279,50 @@ static uint8_t *legacy_decode(uint8_t *buf, const char *devmem, uint32_t &size,
 }
 
 
+#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];
+#   elif defined(__FreeBSD__)
+    char addrstr[KENV_MVALLEN + 1];
+#   endif
+
+    off_t address = 0;
+
+#   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
 
 
@@ -207,9 +330,10 @@ bool xmrig::DmiReader::read()
 {
     size_t size  = 0x20;
     uint8_t *buf = read_file(0, &size, kSysEntryFile);
+    uint8_t *smb = nullptr;
 
     if (buf) {
-        uint8_t *smb = nullptr;
+        smb = nullptr;
 
         if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0) {
             smb = smbios3_decode(buf, kSysTableFile, m_size, m_version, FLAG_NO_FILE_OFFSET);
@@ -222,12 +346,71 @@ bool xmrig::DmiReader::read()
         }
 
         if (smb) {
-            return decode(smb, [smb, buf]() {
-                free(smb);
-                free(buf);
-            });
+            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;
 }

From 9dffcdaddd02752c8a39827521227dcd57f4bc1f Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Tue, 19 Jan 2021 01:45:17 +0700
Subject: [PATCH 05/11] Enable FreeBSD support.

---
 src/hw/dmi/DmiReader_unix.cpp | 3 +--
 src/hw/dmi/dmi.cmake          | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/hw/dmi/DmiReader_unix.cpp b/src/hw/dmi/DmiReader_unix.cpp
index d73e39436..ff57b7a6a 100644
--- a/src/hw/dmi/DmiReader_unix.cpp
+++ b/src/hw/dmi/DmiReader_unix.cpp
@@ -287,12 +287,11 @@ static off_t address_from_efi()
     FILE *efi_systab;
     const char *filename;
     char linebuf[64];
+    off_t address = 0;
 #   elif defined(__FreeBSD__)
     char addrstr[KENV_MVALLEN + 1];
 #   endif
 
-    off_t address = 0;
-
 #   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;
diff --git a/src/hw/dmi/dmi.cmake b/src/hw/dmi/dmi.cmake
index ff4882ce0..e10ec3ed4 100644
--- a/src/hw/dmi/dmi.cmake
+++ b/src/hw/dmi/dmi.cmake
@@ -17,7 +17,7 @@ if (WITH_DMI)
 
     if (XMRIG_OS_WIN)
         list(APPEND SOURCES src/hw/dmi/DmiReader_win.cpp)
-    elseif(XMRIG_OS_LINUX)
+    elseif(XMRIG_OS_LINUX OR XMRIG_OS_FREEBSD)
         list(APPEND SOURCES src/hw/dmi/DmiReader_unix.cpp)
     endif()
 else()

From 24c290963aea6034d7ece6fafdc4480943dd8d7f Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Tue, 19 Jan 2021 14:16:03 +0700
Subject: [PATCH 06/11] Added DMI reader for macOS.

---
 src/Summary.cpp              |  12 ++--
 src/hw/dmi/DmiReader.cpp     |   4 ++
 src/hw/dmi/DmiReader_mac.cpp | 108 +++++++++++++++++++++++++++++++++++
 src/hw/dmi/dmi.cmake         |   4 ++
 4 files changed, 122 insertions(+), 6 deletions(-)
 create mode 100644 src/hw/dmi/DmiReader_mac.cpp

diff --git a/src/Summary.cpp b/src/Summary.cpp
index b925232fd..8118f99d7 100644
--- a/src/Summary.cpp
+++ b/src/Summary.cpp
@@ -147,13 +147,13 @@ static void print_memory()
             continue;
         }
 
-        if (!memory.size()) {
-            Log::print(WHITE_BOLD("   %-13s") "%s: " BLACK_BOLD("<empty>"), "", memory.slot().data());
-            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 (!Cpu::info()->isVM()) {
+            Log::print(WHITE_BOLD("   %-13s") "%s: " BLACK_BOLD("<empty>"), "", memory.slot().data());
         }
-
-        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());
     }
 
     if (reader.board().isValid()) {
diff --git a/src/hw/dmi/DmiReader.cpp b/src/hw/dmi/DmiReader.cpp
index 8993531a6..5c6a9607f 100644
--- a/src/hw/dmi/DmiReader.cpp
+++ b/src/hw/dmi/DmiReader.cpp
@@ -70,6 +70,10 @@ bool xmrig::DmiReader::decode(uint8_t *buf)
         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) {
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/dmi.cmake b/src/hw/dmi/dmi.cmake
index e10ec3ed4..aee0ff9a3 100644
--- a/src/hw/dmi/dmi.cmake
+++ b/src/hw/dmi/dmi.cmake
@@ -19,6 +19,10 @@ if (WITH_DMI)
         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)

From dea5be0a57029074bde06db1faabbcd82be64bb8 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Wed, 20 Jan 2021 00:43:01 +0700
Subject: [PATCH 07/11] Added basic system reader.

---
 src/Summary.cpp          | 8 ++++++--
 src/hw/dmi/DmiBoard.cpp  | 1 -
 src/hw/dmi/DmiReader.cpp | 4 ++++
 src/hw/dmi/DmiReader.h   | 4 +++-
 4 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/Summary.cpp b/src/Summary.cpp
index 8118f99d7..0cbbbbcad 100644
--- a/src/Summary.cpp
+++ b/src/Summary.cpp
@@ -142,6 +142,8 @@ static void print_memory()
         return;
     }
 
+    const bool vm = Cpu::info()->isVM();
+
     for (const auto &memory : reader.memory()) {
         if (!memory.isValid()) {
             continue;
@@ -151,12 +153,14 @@ static void print_memory()
             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 (!Cpu::info()->isVM()) {
+        else if (!vm) {
             Log::print(WHITE_BOLD("   %-13s") "%s: " BLACK_BOLD("<empty>"), "", memory.slot().data());
         }
     }
 
-    if (reader.board().isValid()) {
+    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", reader.board().vendor().data(), reader.board().product().data());
     }
 #   endif
diff --git a/src/hw/dmi/DmiBoard.cpp b/src/hw/dmi/DmiBoard.cpp
index 381865f4e..5ebfd9aa3 100644
--- a/src/hw/dmi/DmiBoard.cpp
+++ b/src/hw/dmi/DmiBoard.cpp
@@ -23,7 +23,6 @@
 #include "hw/dmi/DmiTools.h"
 
 
-
 void xmrig::DmiBoard::decode(dmi_header *h)
 {
     if (h->length < 0x08) {
diff --git a/src/hw/dmi/DmiReader.cpp b/src/hw/dmi/DmiReader.cpp
index 5c6a9607f..9854ff1b4 100644
--- a/src/hw/dmi/DmiReader.cpp
+++ b/src/hw/dmi/DmiReader.cpp
@@ -82,6 +82,10 @@ bool xmrig::DmiReader::decode(uint8_t *buf)
         }
 
         switch (h.type) {
+        case 1:
+            m_system.decode(&h);
+            break;
+
         case 2:
             m_board.decode(&h);
             break;
diff --git a/src/hw/dmi/DmiReader.h b/src/hw/dmi/DmiReader.h
index f140f8676..ccf2311ae 100644
--- a/src/hw/dmi/DmiReader.h
+++ b/src/hw/dmi/DmiReader.h
@@ -38,6 +38,7 @@ 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; }
@@ -51,9 +52,10 @@ private:
     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;
-    std::vector<DmiMemory> m_memory;
 };
 
 

From efc5e5d81128389cad59ea0d9a6258dd717c8c9c Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Wed, 20 Jan 2021 00:45:36 +0700
Subject: [PATCH 08/11] Fix summary.

---
 src/Summary.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Summary.cpp b/src/Summary.cpp
index 0cbbbbcad..e0c4d58e9 100644
--- a/src/Summary.cpp
+++ b/src/Summary.cpp
@@ -161,7 +161,7 @@ static void print_memory()
     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", reader.board().vendor().data(), reader.board().product().data());
+        Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s") WHITE_BOLD("%s") " - " WHITE_BOLD("%s"), "MOTHERBOARD", board.vendor().data(), board.product().data());
     }
 #   endif
 }

From 9a0200790042d22664a39f54c0199f27318c69a5 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Wed, 20 Jan 2021 16:02:48 +0700
Subject: [PATCH 09/11] Added config option "dmi" and command line option
 "--no-dmi".

---
 CMakeLists.txt                       |  2 +-
 src/Summary.cpp                      | 32 ++++++++++-------
 src/Summary.h                        |  4 +--
 src/base/kernel/interfaces/IConfig.h |  5 +--
 src/core/config/Config.cpp           | 38 +++++++++++++++++----
 src/core/config/Config.h             | 28 +++++++++++++--
 src/core/config/ConfigTransform.cpp  | 51 ++++++++++++++--------------
 src/core/config/ConfigTransform.h    |  4 +--
 src/core/config/Config_platform.h    |  5 +++
 src/core/config/usage.h              |  4 +++
 src/hw/dmi/dmi.cmake                 |  4 +++
 11 files changed, 121 insertions(+), 56 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 69f40fcdd..fe411cb1c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,7 +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 reader" 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)
diff --git a/src/Summary.cpp b/src/Summary.cpp
index e0c4d58e9..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
@@ -76,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"));
@@ -92,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();
 
@@ -121,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());
@@ -137,6 +137,10 @@ static void print_memory()
                );
 
 #   ifdef XMRIG_FEATURE_DMI
+    if (!config->isDMI()) {
+        return;
+    }
+
     DmiReader reader;
     if (!reader.read()) {
         return;
@@ -167,7 +171,7 @@ static void print_memory()
 }
 
 
-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",
@@ -209,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/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/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/dmi/dmi.cmake b/src/hw/dmi/dmi.cmake
index aee0ff9a3..5140692a7 100644
--- a/src/hw/dmi/dmi.cmake
+++ b/src/hw/dmi/dmi.cmake
@@ -1,3 +1,7 @@
+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)
 

From 8471f7fad3db29e0765d733335647c63fedc5822 Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Wed, 20 Jan 2021 22:54:02 +0700
Subject: [PATCH 10/11] Added "GET /2/dmi" API endpoint.

---
 CMakeLists.txt                             |  3 +-
 src/base/api/Api.cpp                       | 10 +---
 src/base/api/Api.h                         | 11 +----
 src/base/api/interfaces/IApiListener.h     | 14 +++---
 src/base/api/interfaces/IApiRequest.h      | 16 +++----
 src/base/kernel/interfaces/IBaseListener.h | 18 ++++----
 src/core/Controller.cpp                    | 42 ++++++++---------
 src/core/Controller.h                      | 23 +++++-----
 src/hw/api/HwApi.cpp                       | 47 +++++++++++++++++++
 src/hw/api/HwApi.h                         | 53 ++++++++++++++++++++++
 src/hw/api/api.cmake                       | 11 +++++
 src/hw/dmi/DmiBoard.cpp                    | 16 +++++++
 src/hw/dmi/DmiBoard.h                      |  4 ++
 src/hw/dmi/DmiMemory.cpp                   | 26 +++++++++++
 src/hw/dmi/DmiMemory.h                     |  4 ++
 src/hw/dmi/DmiReader.cpp                   | 34 ++++++++++++++
 src/hw/dmi/DmiReader.h                     |  5 ++
 17 files changed, 263 insertions(+), 74 deletions(-)
 create mode 100644 src/hw/api/HwApi.cpp
 create mode 100644 src/hw/api/HwApi.h
 create mode 100644 src/hw/api/api.cmake

diff --git a/CMakeLists.txt b/CMakeLists.txt
index fe411cb1c..79486e03e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -198,7 +198,8 @@ if (WITH_EMBEDDED_CONFIG)
     add_definitions(/DXMRIG_FEATURE_EMBEDDED_CONFIG)
 endif()
 
-include (src/hw/dmi/dmi.cmake)
+include(src/hw/api/api.cmake)
+include(src/hw/dmi/dmi.cmake)
 
 include_directories(src)
 include_directories(src/3rdparty)
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/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/hw/api/HwApi.cpp b/src/hw/api/HwApi.cpp
new file mode 100644
index 000000000..5aedbf334
--- /dev/null
+++ b/src/hw/api/HwApi.cpp
@@ -0,0 +1,47 @@
+/* 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"
+
+#include "base/io/log/Log.h" // FIXME
+
+
+#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
index 5ebfd9aa3..3cbe3dd9a 100644
--- a/src/hw/dmi/DmiBoard.cpp
+++ b/src/hw/dmi/DmiBoard.cpp
@@ -20,6 +20,7 @@
 
 
 #include "hw/dmi/DmiBoard.h"
+#include "3rdparty/rapidjson/document.h"
 #include "hw/dmi/DmiTools.h"
 
 
@@ -32,3 +33,18 @@ void xmrig::DmiBoard::decode(dmi_header *h)
     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
index dd28a607b..0c64da17c 100644
--- a/src/hw/dmi/DmiBoard.h
+++ b/src/hw/dmi/DmiBoard.h
@@ -42,6 +42,10 @@ public:
 
     void decode(dmi_header *h);
 
+#   ifdef XMRIG_FEATURE_API
+    rapidjson::Value toJSON(rapidjson::Document &doc) const;
+#   endif
+
 private:
     String m_product;
     String m_vendor;
diff --git a/src/hw/dmi/DmiMemory.cpp b/src/hw/dmi/DmiMemory.cpp
index f02a64ecd..5b36e2bae 100644
--- a/src/hw/dmi/DmiMemory.cpp
+++ b/src/hw/dmi/DmiMemory.cpp
@@ -20,6 +20,7 @@
 
 
 #include "hw/dmi/DmiMemory.h"
+#include "3rdparty/rapidjson/document.h"
 #include "hw/dmi/DmiTools.h"
 
 
@@ -190,3 +191,28 @@ 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
index b9a0468b0..badee2cfd 100644
--- a/src/hw/dmi/DmiMemory.h
+++ b/src/hw/dmi/DmiMemory.h
@@ -52,6 +52,10 @@ public:
     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;
diff --git a/src/hw/dmi/DmiReader.cpp b/src/hw/dmi/DmiReader.cpp
index 9854ff1b4..18211759a 100644
--- a/src/hw/dmi/DmiReader.cpp
+++ b/src/hw/dmi/DmiReader.cpp
@@ -20,6 +20,8 @@
 
 
 #include "hw/dmi/DmiReader.h"
+#include "3rdparty/fmt/core.h"
+#include "3rdparty/rapidjson/document.h"
 #include "hw/dmi/DmiTools.h"
 
 
@@ -38,6 +40,38 @@ static void dmi_get_header(dmi_header *h, uint8_t *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);
diff --git a/src/hw/dmi/DmiReader.h b/src/hw/dmi/DmiReader.h
index ccf2311ae..a4f7eb8a7 100644
--- a/src/hw/dmi/DmiReader.h
+++ b/src/hw/dmi/DmiReader.h
@@ -45,6 +45,11 @@ public:
 
     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()>;
 

From ef8cc28f3f250eb3adcd380a3da253a83102ab8d Mon Sep 17 00:00:00 2001
From: XMRig <support@xmrig.com>
Date: Thu, 21 Jan 2021 23:22:01 +0700
Subject: [PATCH 11/11] Added DMI data to online benchmark.

---
 src/base/net/stratum/Pools.cpp                 |  6 +++---
 src/base/net/stratum/Pools.h                   |  4 ++--
 src/base/net/stratum/benchmark/BenchClient.cpp | 17 +++++++++++++++--
 src/base/net/stratum/benchmark/BenchClient.h   |  4 ++--
 src/base/net/stratum/benchmark/BenchConfig.cpp | 11 ++++++-----
 src/base/net/stratum/benchmark/BenchConfig.h   | 10 ++++++----
 src/hw/api/HwApi.cpp                           |  2 --
 7 files changed, 34 insertions(+), 20 deletions(-)

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/hw/api/HwApi.cpp b/src/hw/api/HwApi.cpp
index 5aedbf334..fed5de3f9 100644
--- a/src/hw/api/HwApi.cpp
+++ b/src/hw/api/HwApi.cpp
@@ -21,8 +21,6 @@
 #include "base/api/interfaces/IApiRequest.h"
 #include "base/tools/String.h"
 
-#include "base/io/log/Log.h" // FIXME
-
 
 #ifdef XMRIG_FEATURE_DMI
 #   include "hw/dmi/DmiReader.h"