added enable all cores command, added disable cores command, as a byproduct of that added capability for WMI commands in general, fixed instantiation of winring0 driver

This commit is contained in:
rawhide kobayashi 2025-03-18 20:51:47 -05:00
parent d36decf6db
commit ba192c9061
Signed by: rawhide_k
GPG Key ID: E71F77DDBC513FD7
5 changed files with 297 additions and 38 deletions

21
ryzen-smu-cli/LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
Copyright (c) 2007-2009 OpenLibSys.org. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,48 +1,195 @@
using System.CommandLine;
using System.Management;
using ZenStates.Core;
class Program
namespace ryzen_smu_cli
{
private static readonly Cpu ryzen = new();
static int Main(string[] args)
class Program
{
private static readonly Cpu ryzen = new();
var rootCommand = new RootCommand("A CLI for the Ryzen SMU.");
private static readonly string wmiAMDACPI = "AMD_ACPI";
private static readonly string wmiScope = "root\\wmi";
private static ManagementObject? classInstance;
private static string? instanceName;
private static ManagementBaseObject? pack;
var pboOffset = new Option<string>("--offset", "Specify a core, or list of cores, and their PBO offset(s), in a fashion similar to taskset. e.g. 0:-10,1:5,2:-20,14:-25");
private static List<WmiCmdListItem> availableCommands = [];
rootCommand.AddOption(pboOffset);
rootCommand.SetHandler((offsetArgs) =>
private static bool wmiPopulated = false;
private static bool rebootFlag = false;
static int Main(string[] args)
{
RunPBOOffset(offsetArgs);
}, pboOffset);
var rootCommand = new RootCommand("A CLI for the Ryzen SMU.");
return rootCommand.Invoke(args);
}
var pboOffset = new Option<string>("--offset", "Specify a zero-indexed core, or list of cores, and their PBO offset(s), in a fashion similar to taskset. e.g. 0:-10,1:5,2:-20,14:-25");
var disableCores = new Option<string>("--disable-cores", "Specify a zero-indexed list of cores to disable. e.g. 0,1,4,7,12,15. This setting does not take into account any current core disablement. All cores you wish to disable must be specified. Any that are unspecified will be enabled. This option requires a reboot.");
var enableCores = new Option<bool>("--enable-all-cores", "Enable all cores.");
private static void RunPBOOffset(string offsetArgs)
{
string[] arg = offsetArgs.Split(',');
rootCommand.AddOption(pboOffset);
rootCommand.AddOption(disableCores);
rootCommand.AddOption(enableCores);
for (int i = 0; i < arg.Length; i++)
{
ApplySingleCorePBOOffset(Convert.ToInt32(arg[i].Split(':')[0]), Convert.ToInt32(arg[i].Split(':')[1]));
rootCommand.SetHandler((offsetArgs, coreDisableArgs, enableAll) =>
{
if (!string.IsNullOrEmpty(offsetArgs)) ApplyPBOOffset(offsetArgs);
if (!string.IsNullOrEmpty(coreDisableArgs)) ApplyDisableCores(coreDisableArgs);
if (enableAll) ApplyDisableCores();
}, pboOffset, disableCores, enableCores);
if (args.Length == 0)
{
rootCommand.Invoke("--help");
}
else
{
rootCommand.Invoke(args);
}
ryzen.Dispose();
if (rebootFlag) Console.WriteLine("A reboot is required for changes to take effect.");
return 0;
}
}
private static void ApplySingleCorePBOOffset(int coreNumber, int value)
{
// Magic numbers from SMUDebugTool
// This does some bitshifting calculations to get the mask for individual cores for chips with up to two CCDs
// I'm not sure if it would work with more, in theory. It's unclear to me based on the github issues.
int mapIndex = coreNumber < 8 ? 0 : 1;
if ((~ryzen.info.topology.coreDisableMap[mapIndex] >> coreNumber % 8 & 1) == 1)
private static string GetWmiInstanceName()
{
ryzen.SetPsmMarginSingleCore((uint)(((mapIndex << 8) | coreNumber % 8 & 0xF) << 20), value);
Console.WriteLine($"Set core {coreNumber} to offset {value}!");
try
{
instanceName = WMI.GetInstanceName(wmiScope, wmiAMDACPI);
}
catch
{
// ignored
}
return instanceName;
}
private static void PopulateWmiFunctions()
{
try
{
instanceName = GetWmiInstanceName();
classInstance = new ManagementObject(wmiScope,
$"{wmiAMDACPI}.InstanceName='{instanceName}'",
null);
// Get function names with their IDs
string[] functionObjects = { "GetObjectID", "GetObjectID2" };
var index = 1;
foreach (var functionObject in functionObjects)
{
try
{
pack = WMI.InvokeMethodAndGetValue(classInstance, functionObject, "pack", null, 0);
if (pack != null)
{
var ID = (uint[])pack.GetPropertyValue("ID");
var IDString = (string[])pack.GetPropertyValue("IDString");
var Length = (byte)pack.GetPropertyValue("Length");
for (var i = 0; i < Length; ++i)
{
if (IDString[i] == "")
break;
WmiCmdListItem item = new($"{IDString[i] + ": "}{ID[i]:X8}", ID[i], !IDString[i].StartsWith("Get"));
availableCommands.Add(item);
}
}
}
catch
{
// ignored
}
index++;
}
}
catch
{
// ignored
}
rebootFlag = true;
wmiPopulated = true;
}
private static void ApplyPBOOffset(string offsetArgs)
{
string[] arg = offsetArgs.Split(',');
for (int i = 0; i < arg.Length; i++)
{
int core = Convert.ToInt32(arg[i].Split(':')[0]);
int offset = Convert.ToInt32(arg[i].Split(':')[1]);
// Magic numbers from SMUDebugTool
// This does some bitshifting calculations to get the mask for individual cores for chips with up to two CCDs
// I'm not sure if it would work with more, in theory. It's unclear to me based on the github issues.
int mapIndex = core < 8 ? 0 : 1;
if ((~ryzen.info.topology.coreDisableMap[mapIndex] >> core % 8 & 1) == 1)
{
ryzen.SetPsmMarginSingleCore((uint)(((mapIndex << 8) | core % 8 & 0xF) << 20), offset);
Console.WriteLine($"Set core {core} offset to {offset}!");
}
else
{
Console.WriteLine($"Unable to set offset on disabled core {core}.");
}
}
}
private static void ApplyDisableCores(string coreArgs = "Enable")
{
if (!wmiPopulated) PopulateWmiFunctions();
// More magic from SMUDebugTool...
// uintccd2 = 0x8200; ? :)
uint[] ccds = [0x8000, 0x8100];
var cmdItem = availableCommands.FirstOrDefault(item => item.text.Contains("Software Downcore Config"));
if (cmdItem != null)
{
for (int i = 0; i < ccds.Length; i++)
{
if (coreArgs != "Enable")
{
int[] arg = [.. coreArgs.Split(',').Select(int.Parse)];
for (int x = 0; x < 8; x++)
{
if (arg.Contains(x + (i * 8)))
{
ccds[i] = Utils.SetBits(ccds[i], x, 1, 1);
}
}
}
// Unreadable garbage... But it's my unreadable garbage. It just prints the bitmaps in the expected,
// human order.
Console.WriteLine($"New core disablement bitmap for CCD{i} (reversed lower half): {new string([.. Convert.ToString((int)(ccds[i] & 0xFF), 2).PadLeft(8, '0').Reverse()])}");
WMI.RunCommand(classInstance, cmdItem.value, ccds[i]);
}
}
else
{
Console.WriteLine("Something has gone terribly wrong, the downcore config option is not present.");
}
}
}
}

View File

@ -0,0 +1,22 @@
namespace ryzen_smu_cli
{
public class WmiCmdListItem
{
public uint value { get; }
public string text { get; }
public bool isSet { get; }
public WmiCmdListItem(string text, uint value, bool isSet = false)
{
this.text = text;
this.value = value;
this.isSet = isSet;
}
public override string ToString()
{
return this.text;
}
}
}

View File

@ -0,0 +1,67 @@
END USER LICENSE AGREEMENT
Software License Agreement for WinIo
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files.
IMPORTANT- PLEASE READ CAREFULLY: BY INSTALLING THE SOFTWARE (AS DEFINED BELOW),
OR COPYING THE SOFTWARE, YOU (EITHER ON BEHALF OF YOURSELF AS AN INDIVIDUAL OR
ON BEHALF OF AN ENTITY AS ITS AUTHORIZED REPRESENTATIVE) AGREE TO ALL OF THE
TERMS OF THIS END USER LICENSE AGREEMENT ("AGREEMENT") REGARDING YOUR USE OF
THE SOFTWARE. IF YOU DO NOT AGREE WITH ALL OF THE TERMS OF THIS AGREEMENT, DO
NOT INSTALL, COPY OR OTHERWISE USE THE SOFTWARE.
1. GRANT OF LICENSE: Subject to the terms below, Yariv Kaplan ("AUTHOR") hereby
grants you a non-exclusive, non-transferable, non-assignable license to install
and to use the downloadable version of WinIo ("SOFTWARE").
a. Redistributable Code. You may reproduce and distribute the object code form
of the SOFTWARE solely in conjunction with, and as part of, your application
("Permitted Application"); provided that you comply with the following:
If you redistribute any portion of the Redistributable Code, you agree that:
(i) you will only distribute the Redistributable Code in conjunction with, and
as part of, your Permitted Application which adds significant functionality to
the Redistributable Code and that distribution of the Permitted Application does
not compete with the AUTHOR's distribution of the SOFTWARE;
(ii) you will include a valid copyright notice on your Permitted Application;
(iii) you will not permit further redistribution of the Redistributable Code;
(iv) you will indemnify, hold harmless, and defend the AUTHOR from and against
any claims or lawsuits, including attorneys' fees, that arise or result from
the use or distribution of your Permitted Application.
b. License to use Source Code. You may not sell, lease, rent, transfer or
sublicense the source code of this SOFTWARE.
2. MODIFICATION: SOFTWARE Source Code may be modified without the prior written
permission of the AUTHOR. Any modifications made to the SOFTWARE will continue
to be subject to the terms and conditions of this AGREEMENT.
3. COPYRIGHT: All rights, title, and copyrights in and to the SOFTWARE and any
copies of the SOFTWARE are owned by the AUTHOR. The SOFTWARE is protected by
copyright laws and international treaty provisions. Therefore, you must treat
the SOFTWARE like any other copyrighted material.
4. TITLE: You acknowledge that no title to the intellectual property in the
SOFTWARE is transferred to you. Title, ownership, rights, and intellectual
property rights in and to the SOFTWARE shall remain the exclusive property of
the AUTHOR. The SOFTWARE is protected by copyright laws of the United States
and international treaties.
5. LIMITATION OF LIABILITY: You must assume the entire risk of using the
SOFTWARE.
IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHOR
HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
AND THE AUTHOR HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS.

View File

@ -14,25 +14,27 @@
</PropertyGroup>
<PropertyGroup>
<!-- Set build configuration to Release by default -->
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<!-- Enable single-file publishing -->
<PublishSingleFile>true</PublishSingleFile>
<!-- Target runtime -->
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<!-- Disable self-contained deployment -->
<SelfContained>false</SelfContained>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="include\ZenStates-Core\External\WinRing0\WinRing0.sys">
<LogicalName>ZenStates.Core.WinRing0.sys</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="include\ZenStates-Core\External\WinRing0\WinRing0x64.sys">
<LogicalName>ZenStates.Core.WinRing0x64.sys</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<!-- Included for the ZenStates-Core submodule...-->
<PackageReference Include="System.Management" Version="6.0.0" />
<!-- Included for the ZenStates-Core submodule...-->
<PackageReference Include="System.ServiceProcess.ServiceController" Version="6.0.0" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
<PackageReference Include="System.Threading.AccessControl" Version="6.0.0" />