* Remove retry + proper identifier * Update LibreHardwareMonitorLib.csproj * Revert "Update LibreHardwareMonitorLib.csproj" This reverts commit 185aa2dbd3d338da79aff8bfa9419f016d107e77. * Add safer retry logic for MemoryGroup * Move kernel driver assignation in instance ctor instead of static (one time) ctor, since Ring0 can get closed and reopened multiple times in the lifetime of an application. * Add Task based retry logic with try catch + exception reporting + hardware changed event * Update MemoryGroup.cs * Update RAMSPDToolkitDriver.cs * Update RAMSPDToolkitDriver.cs * Mutate _hardware field to avoid enumeration exceptions * Add Report + set configureAwait on the Delay.
415 lines
13 KiB
C#
415 lines
13 KiB
C#
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
// Copyright (C) LibreHardwareMonitor and Contributors.
|
|
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
|
|
// All Rights Reserved.
|
|
|
|
using System.Runtime.InteropServices;
|
|
using RAMSPDToolkit.Windows.Driver;
|
|
|
|
using IOCC = LibreHardwareMonitor.Interop.Ring0;
|
|
|
|
namespace LibreHardwareMonitor.Hardware
|
|
{
|
|
/// <summary>
|
|
/// Implementation of <see cref="IDriver"/> interface for RAMSPDToolkit.
|
|
/// </summary>
|
|
internal class RAMSPDToolkitDriver : IDriver
|
|
{
|
|
private KernelDriver _kernelDriver;
|
|
|
|
private const byte PCI_MAX_NUMBER_OF_BUS = 255;
|
|
private const byte PCI_NUMBER_OF_DEVICE = 32;
|
|
private const byte PCI_NUMBER_OF_FUNCTION = 8;
|
|
|
|
public bool IsOpen => _kernelDriver?.IsOpen ?? false;
|
|
|
|
public RAMSPDToolkitDriver(KernelDriver kernelDriver)
|
|
{
|
|
_kernelDriver = kernelDriver;
|
|
}
|
|
|
|
//Driver is being managed internally by other classes, so nothing to do in Load + Unload
|
|
|
|
public bool Load()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public void Unload()
|
|
{
|
|
}
|
|
|
|
public byte ReadIoPortByte(ushort port)
|
|
{
|
|
byte value = 0;
|
|
|
|
ReadIoPortByteEx(port, ref value);
|
|
|
|
return value;
|
|
}
|
|
|
|
public ushort ReadIoPortWord(ushort port)
|
|
{
|
|
ushort value = 0;
|
|
|
|
ReadIoPortWordEx(port, ref value);
|
|
|
|
return value;
|
|
}
|
|
|
|
public uint ReadIoPortDword(ushort port)
|
|
{
|
|
uint value = 0;
|
|
|
|
ReadIoPortDwordEx(port, ref value);
|
|
|
|
return value;
|
|
}
|
|
|
|
public bool ReadIoPortByteEx(ushort port, ref byte value)
|
|
{
|
|
if (!IsOpen)
|
|
return false;
|
|
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value);
|
|
}
|
|
|
|
public bool ReadIoPortWordEx(ushort port, ref ushort value)
|
|
{
|
|
if (!IsOpen)
|
|
return false;
|
|
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_READ_IO_PORT_WORD, port, ref value);
|
|
}
|
|
|
|
public bool ReadIoPortDwordEx(ushort port, ref uint value)
|
|
{
|
|
if (!IsOpen)
|
|
return false;
|
|
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_READ_IO_PORT_DWORD, port, ref value);
|
|
}
|
|
|
|
public void WriteIoPortByte(ushort port, byte value)
|
|
{
|
|
WriteIoPortByteEx(port, value);
|
|
}
|
|
|
|
public void WriteIoPortWord(ushort port, ushort value)
|
|
{
|
|
WriteIoPortWordEx(port, value);
|
|
}
|
|
|
|
public void WriteIoPortDword(ushort port, uint value)
|
|
{
|
|
WriteIoPortDwordEx(port, value);
|
|
}
|
|
|
|
public bool WriteIoPortByteEx(ushort port, byte value)
|
|
{
|
|
if (!IsOpen)
|
|
return false;
|
|
|
|
var input = new WriteIoPortInputByte { PortNumber = port, Value = value };
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_WRITE_IO_PORT_BYTE, input);
|
|
}
|
|
|
|
public bool WriteIoPortWordEx(ushort port, ushort value)
|
|
{
|
|
if (!IsOpen)
|
|
return false;
|
|
|
|
var input = new WriteIoPortInputWord { PortNumber = port, Value = value };
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_WRITE_IO_PORT_WORD, input);
|
|
}
|
|
|
|
public bool WriteIoPortDwordEx(ushort port, uint value)
|
|
{
|
|
if (!IsOpen)
|
|
return false;
|
|
|
|
var input = new WriteIoPortInputDword { PortNumber = port, Value = value };
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_WRITE_IO_PORT_DWORD, input);
|
|
}
|
|
|
|
public uint FindPciDeviceById(ushort vendorId, ushort deviceId, byte index)
|
|
{
|
|
if (!IsOpen)
|
|
return uint.MaxValue;
|
|
|
|
if (vendorId == ushort.MaxValue)
|
|
{
|
|
return uint.MaxValue;
|
|
}
|
|
|
|
uint count = 0;
|
|
|
|
for (byte bus = 0; bus < PCI_MAX_NUMBER_OF_BUS; ++bus)
|
|
{
|
|
for (byte dev = 0; dev < PCI_NUMBER_OF_DEVICE; ++dev)
|
|
{
|
|
bool multiFuncFlag = false;
|
|
|
|
for (byte func = 0; func < PCI_NUMBER_OF_FUNCTION; ++func)
|
|
{
|
|
if (!multiFuncFlag && func > 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
uint pciAddress = Ring0.GetPciAddress(bus, dev, func);
|
|
|
|
uint id = 0;
|
|
|
|
if (PciConfigRead(pciAddress, 0, ref id))
|
|
{
|
|
if (func == 0) //Is Multi Function Device
|
|
{
|
|
byte type = 0;
|
|
|
|
if (PciConfigRead(pciAddress, 0x0E, ref type))
|
|
{
|
|
if ((type & 0x80) != 0)
|
|
{
|
|
multiFuncFlag = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (id == (vendorId | ((uint)deviceId << 16)))
|
|
{
|
|
if (count == index)
|
|
{
|
|
return pciAddress;
|
|
}
|
|
|
|
++count;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return uint.MaxValue;
|
|
}
|
|
|
|
public uint FindPciDeviceByClass(byte baseClass, byte subClass, byte programIf, byte index)
|
|
{
|
|
if (!IsOpen)
|
|
return uint.MaxValue;
|
|
|
|
uint count = 0;
|
|
|
|
for (byte bus = 0; bus < PCI_MAX_NUMBER_OF_BUS; ++bus)
|
|
{
|
|
for (byte dev = 0; dev < PCI_NUMBER_OF_DEVICE; ++dev)
|
|
{
|
|
bool multiFuncFlag = false;
|
|
|
|
for (byte func = 0; func < PCI_NUMBER_OF_FUNCTION; ++func)
|
|
{
|
|
if (!multiFuncFlag && func > 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
uint pciAddress = Ring0.GetPciAddress(bus, dev, func);
|
|
|
|
var conf = new Conf();
|
|
|
|
if (PciConfigRead(pciAddress, 0, ref conf))
|
|
{
|
|
if (func == 0) //Is Multi Function Device
|
|
{
|
|
byte type = 0;
|
|
|
|
if (PciConfigRead(pciAddress, 0x0E, ref type))
|
|
{
|
|
if ((type & 0x80) != 0)
|
|
{
|
|
multiFuncFlag = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
var temp = (uint)baseClass << 24 | (uint)subClass << 16 | (uint)programIf << 8;
|
|
|
|
if ((conf.C & 0xFFFFFF00) == temp)
|
|
{
|
|
if (count == index)
|
|
{
|
|
return pciAddress;
|
|
}
|
|
|
|
++count;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return uint.MaxValue;
|
|
}
|
|
|
|
public byte ReadPciConfigByte(uint pciAddress, byte regAddress)
|
|
{
|
|
byte value = 0;
|
|
|
|
if (ReadPciConfigByteEx(pciAddress, regAddress, ref value))
|
|
{
|
|
return value;
|
|
}
|
|
else
|
|
{
|
|
return byte.MaxValue;
|
|
}
|
|
}
|
|
|
|
public ushort ReadPciConfigWord(uint pciAddress, byte regAddress)
|
|
{
|
|
ushort value = 0;
|
|
|
|
if (ReadPciConfigWordEx(pciAddress, regAddress, ref value))
|
|
{
|
|
return value;
|
|
}
|
|
else
|
|
{
|
|
return ushort.MaxValue;
|
|
}
|
|
}
|
|
|
|
public uint ReadPciConfigDword(uint pciAddress, byte regAddress)
|
|
{
|
|
uint value = 0;
|
|
|
|
if (ReadPciConfigDwordEx(pciAddress, regAddress, ref value))
|
|
{
|
|
return value;
|
|
}
|
|
else
|
|
{
|
|
return uint.MaxValue;
|
|
}
|
|
}
|
|
|
|
public bool ReadPciConfigByteEx(uint pciAddress, uint regAddress, ref byte value)
|
|
{
|
|
return PciConfigRead(pciAddress, regAddress, ref value);
|
|
}
|
|
|
|
public bool ReadPciConfigWordEx(uint pciAddress, uint regAddress, ref ushort value)
|
|
{
|
|
return PciConfigRead(pciAddress, regAddress, ref value);
|
|
}
|
|
|
|
public bool ReadPciConfigDwordEx(uint pciAddress, uint regAddress, ref uint value)
|
|
{
|
|
return PciConfigRead(pciAddress, regAddress, ref value);
|
|
}
|
|
|
|
public void WritePciConfigByte(uint pciAddress, byte regAddress, byte value)
|
|
{
|
|
WritePciConfigByteEx(pciAddress, regAddress, value);
|
|
}
|
|
|
|
public void WritePciConfigWord(uint pciAddress, byte regAddress, ushort value)
|
|
{
|
|
WritePciConfigWordEx(pciAddress, regAddress, value);
|
|
}
|
|
|
|
public void WritePciConfigDword(uint pciAddress, byte regAddress, uint value)
|
|
{
|
|
WritePciConfigDwordEx(pciAddress, regAddress, value);
|
|
}
|
|
|
|
public bool WritePciConfigByteEx(uint pciAddress, uint regAddress, byte value)
|
|
{
|
|
var input = new WritePciConfigInputByte { PciAddress = pciAddress, RegAddress = regAddress, Value = value };
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_WRITE_PCI_CONFIG, input);
|
|
}
|
|
|
|
public bool WritePciConfigWordEx(uint pciAddress, uint regAddress, ushort value)
|
|
{
|
|
var input = new WritePciConfigInputWord { PciAddress = pciAddress, RegAddress = regAddress, Value = value };
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_WRITE_PCI_CONFIG, input);
|
|
}
|
|
|
|
public bool WritePciConfigDwordEx(uint pciAddress, uint regAddress, uint value)
|
|
{
|
|
var input = new WritePciConfigInputDword { PciAddress = pciAddress, RegAddress = regAddress, Value = value };
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_WRITE_PCI_CONFIG, input);
|
|
}
|
|
|
|
private bool PciConfigRead<TValue>(uint pciAddress, uint regAddress, ref TValue value)
|
|
where TValue : struct
|
|
{
|
|
var input = new ReadPciConfigInput { PciAddress = pciAddress, RegAddress = regAddress };
|
|
return _kernelDriver.DeviceIOControl(IOCC.IOCTL_OLS_READ_PCI_CONFIG, input, ref value);
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
private struct WriteIoPortInputByte
|
|
{
|
|
public uint PortNumber;
|
|
public byte Value;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
private struct WriteIoPortInputWord
|
|
{
|
|
public uint PortNumber;
|
|
public ushort Value;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
private struct WriteIoPortInputDword
|
|
{
|
|
public uint PortNumber;
|
|
public uint Value;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
private struct ReadPciConfigInput
|
|
{
|
|
public uint PciAddress;
|
|
public uint RegAddress;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
private struct WritePciConfigInputByte
|
|
{
|
|
public uint PciAddress;
|
|
public uint RegAddress;
|
|
public byte Value;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
private struct WritePciConfigInputWord
|
|
{
|
|
public uint PciAddress;
|
|
public uint RegAddress;
|
|
public ushort Value;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
private struct WritePciConfigInputDword
|
|
{
|
|
public uint PciAddress;
|
|
public uint RegAddress;
|
|
public uint Value;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
private struct Conf
|
|
{
|
|
public uint A;
|
|
public uint B;
|
|
public uint C;
|
|
}
|
|
}
|
|
}
|