All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mario Limonciello <mario.limonciello@amd.com>
To: Tom Lendacky <thomas.lendacky@amd.com>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	"David S . Miller" <davem@davemloft.net>
Cc: John Allen <john.allen@amd.com>, <linux-crypto@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>,
	Mario Limonciello <mario.limonciello@amd.com>
Subject: [PATCH v3 08/10] crypto: ccp: Add a sample script for Dynamic Boost Control
Date: Thu, 18 May 2023 22:24:46 -0500	[thread overview]
Message-ID: <20230519032448.94279-9-mario.limonciello@amd.com> (raw)
In-Reply-To: <20230519032448.94279-1-mario.limonciello@amd.com>

Dynamic Boost Control is utilized by userspace with a collection
of 2 R/W IOCTLs and 1 W IOCTL. Userspace needs to prepare buffers
with the appropriate signature data and details of the request.

To allow rapid prototyping and testing this interface, add a python3
command line script that can validate the functionality of these
IOCTLs.

NOTE: This script does *not* generate signatures.  They will need to
be prepared separately and passed as arguments.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 tools/crypto/ccp/.gitignore |   1 +
 tools/crypto/ccp/dbc.py     |  98 ++++++++++++++++++++++++++++
 tools/crypto/ccp/dbc_cli.py | 123 ++++++++++++++++++++++++++++++++++++
 3 files changed, 222 insertions(+)
 create mode 100644 tools/crypto/ccp/.gitignore
 create mode 100644 tools/crypto/ccp/dbc.py
 create mode 100755 tools/crypto/ccp/dbc_cli.py

diff --git a/tools/crypto/ccp/.gitignore b/tools/crypto/ccp/.gitignore
new file mode 100644
index 000000000000..bee8a64b79a9
--- /dev/null
+++ b/tools/crypto/ccp/.gitignore
@@ -0,0 +1 @@
+__pycache__
diff --git a/tools/crypto/ccp/dbc.py b/tools/crypto/ccp/dbc.py
new file mode 100644
index 000000000000..f1b7342060b1
--- /dev/null
+++ b/tools/crypto/ccp/dbc.py
@@ -0,0 +1,98 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0
+
+from ioctl_opt import IOWR, IOW
+import ctypes
+import fcntl
+
+DBC_UID_SIZE = 16
+DBC_NONCE_SIZE = 16
+DBC_SIG_SIZE = 32
+
+PARAM_GET_FMAX_CAP = (0x3,)
+PARAM_SET_FMAX_CAP = (0x4,)
+PARAM_GET_PWR_CAP = (0x5,)
+PARAM_SET_PWR_CAP = (0x6,)
+PARAM_GET_GFX_MODE = (0x7,)
+PARAM_SET_GFX_MODE = (0x8,)
+PARAM_GET_CURR_TEMP = (0x9,)
+PARAM_GET_FMAX_MAX = (0xA,)
+PARAM_GET_FMAX_MIN = (0xB,)
+PARAM_GET_SOC_PWR_MAX = (0xC,)
+PARAM_GET_SOC_PWR_MIN = (0xD,)
+PARAM_GET_SOC_PWR_CUR = (0xE,)
+
+DEVICE_NODE = "/dev/dbc"
+
+
+class _dbc_get_nonce(ctypes.Structure):
+    _fields_ = [
+        ("auth_needed", ctypes.c_uint32),
+        ("nonce", ctypes.c_uint8 * DBC_NONCE_SIZE),
+        ("signature", ctypes.c_uint8 * DBC_SIG_SIZE),
+    ]
+
+
+class _dbc_set_uid(ctypes.Structure):
+    _fields_ = [
+        ("uid", ctypes.c_uint8 * DBC_UID_SIZE),
+        ("signature", ctypes.c_uint8 * DBC_SIG_SIZE),
+    ]
+
+
+class _dbc_param(ctypes.Structure):
+    _fields_ = [
+        ("msg_index", ctypes.c_uint32),
+        ("parameter", ctypes.c_uint32),
+        ("signature", ctypes.c_uint8 * DBC_SIG_SIZE),
+    ]
+
+
+DBCIOCNONCE = IOWR(ord("D"), 0x01, _dbc_get_nonce)
+DBCIOCUID = IOW(ord("D"), 0x02, _dbc_set_uid)
+DBCIOCPARAM = IOWR(ord("D"), 0x03, _dbc_param)
+
+
+def get_nonce(device, signature):
+    nonce = _dbc_get_nonce()
+    if signature:
+        nonce.auth_needed = 1
+        tmp = ctypes.c_ubyte * len(signature)
+        nonce.signature = tmp.from_buffer_copy(bytes(signature, "ascii"))
+    result = fcntl.ioctl(device, DBCIOCNONCE, nonce, True)
+    if result < 0:
+        raise IOError(result)
+    return nonce
+
+
+def set_uid(device, new_uid, signature):
+    uid = _dbc_set_uid()
+    if not signature:
+        raise ValueError("Signature required")
+    if not new_uid:
+        raise ValueError("UID required")
+    tmp = ctypes.c_ubyte * len(signature)
+    tmp2 = ctypes.c_ubyte * len(new_uid)
+    uid.signature = tmp.from_buffer_copy(bytes(signature, "ascii"))
+    uid.uid = tmp2.from_buffer_copy(bytes(new_uid, "ascii"))
+    result = fcntl.ioctl(device, DBCIOCUID, uid, True)
+    if result < 0:
+        raise IOError(result)
+    return True
+
+
+def process_param(device, message, signature, data=None):
+    param = _dbc_param()
+    if not signature:
+        raise ValueError("Signature required")
+    if type(message) != tuple:
+        raise ValueError("Expected message tuple")
+    tmp = ctypes.c_ubyte * len(signature)
+    param.signature = tmp.from_buffer_copy(bytes(signature, "ascii"))
+    param.msg_index = message[0]
+    if data:
+        param.parameter = data
+    result = fcntl.ioctl(device, DBCIOCPARAM, param, True)
+    if result < 0:
+        raise IOError(result)
+    return param
diff --git a/tools/crypto/ccp/dbc_cli.py b/tools/crypto/ccp/dbc_cli.py
new file mode 100755
index 000000000000..2dbefc2b7ed3
--- /dev/null
+++ b/tools/crypto/ccp/dbc_cli.py
@@ -0,0 +1,123 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: GPL-2.0
+import argparse
+import binascii
+import os
+import errno
+from dbc import *
+
+ERRORS = {
+    errno.EACCES: "Access is denied",
+    errno.E2BIG: "Excess data provided",
+    errno.EINVAL: "Bad parameters",
+    errno.EAGAIN: "Bad state",
+    errno.ENOENT: "Not implemented or message failure",
+    errno.EBUSY: "Busy",
+    errno.ENFILE: "Overflow",
+    errno.EPERM: "Signature invalid",
+}
+
+messages = {
+    "get-fmax-cap": PARAM_GET_FMAX_CAP,
+    "set-fmax-cap": PARAM_SET_FMAX_CAP,
+    "get-power-cap": PARAM_GET_PWR_CAP,
+    "set-power-cap": PARAM_SET_PWR_CAP,
+    "get-graphics-mode": PARAM_GET_GFX_MODE,
+    "set-graphics-mode": PARAM_SET_GFX_MODE,
+    "get-current-temp": PARAM_GET_CURR_TEMP,
+    "get-fmax-max": PARAM_GET_FMAX_MAX,
+    "get-fmax-min": PARAM_GET_FMAX_MAX,
+    "get-soc-power-max": PARAM_GET_SOC_PWR_MAX,
+    "get-soc-power-min": PARAM_GET_SOC_PWR_MIN,
+    "get-soc-power-cur": PARAM_GET_SOC_PWR_CUR,
+}
+
+
+def _pretty_buffer(ba):
+    return str(binascii.hexlify(ba, " "))
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description="Dynamic Boost control command line interface"
+    )
+    parser.add_argument(
+        "command",
+        choices=["get-nonce", "get-param", "set-param", "set-uid"],
+        help="Command to send",
+    )
+    parser.add_argument("--device", default="/dev/dbc", help="Device to operate")
+    parser.add_argument("--signature", help="Signature for command")
+    parser.add_argument("--message", choices=messages.keys(), help="Message index")
+    parser.add_argument("--data", help="Argument to pass to message")
+    parser.add_argument("--uid", help="UID to pass")
+    return parser.parse_args()
+
+
+def pretty_error(code):
+    if code in ERRORS:
+        print(ERRORS[code])
+    else:
+        print("failed with return code %d" % code)
+
+
+if __name__ == "__main__":
+    args = parse_args()
+    data = 0
+    if not os.path.exists(args.device):
+        raise IOError("Missing device {device}".format(device=args.device))
+    if args.signature and len(args.signature) != DBC_SIG_SIZE:
+        raise ValueError(
+            "Invalid signature length %d (expected %d)"
+            % (len(args.signature), DBC_SIG_SIZE)
+        )
+    if args.uid and len(args.uid) != DBC_UID_SIZE:
+        raise ValueError(
+            "Invalid UID length %d (expected %d)" % (len(args.uid), DBC_UID_SIZE)
+        )
+    if args.data:
+        try:
+            data = int(args.data, 10)
+        except ValueError:
+            data = int(args.data, 16)
+
+    with open(args.device) as d:
+        if args.command == "get-nonce":
+            try:
+                nonce = get_nonce(d, args.signature)
+                print("Nonce: %s" % _pretty_buffer(bytes(nonce.nonce)))
+            except OSError as e:
+                pretty_error(e.errno)
+        elif args.command == "set-uid":
+            try:
+                result = set_uid(d, args.uid, args.signature)
+                if result:
+                    print("Set UID")
+            except OSError as e:
+                pretty_error(e.errno)
+        elif args.command == "get-param":
+            if not args.message or args.message.startswith("set"):
+                raise ValueError("Invalid message %s" % args.message)
+            try:
+                param = process_param(d, messages[args.message], args.signature)
+                print(
+                    "Parameter: {par}, response signature {sig}".format(
+                        par=param.parameter,
+                        sig=_pretty_buffer(bytes(param.signature)),
+                    )
+                )
+            except OSError as e:
+                pretty_error(e.errno)
+        elif args.command == "set-param":
+            if not args.message or args.message.startswith("get"):
+                raise ValueError("Invalid message %s" % args.message)
+            try:
+                param = process_param(d, messages[args.message], args.signature, data)
+                print(
+                    "Parameter: {par}, response signature {sig}".format(
+                        par=param.parameter,
+                        sig=_pretty_buffer(bytes(param.signature)),
+                    )
+                )
+            except OSError as e:
+                pretty_error(e.errno)
-- 
2.34.1


  parent reply	other threads:[~2023-05-19 17:30 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-19  3:24 [PATCH v3 00/10] Add dynamic boost control support Mario Limonciello
2023-05-19  3:24 ` [PATCH v3 01/10] crypto: ccp: Rename macro for security attributes Mario Limonciello
2023-05-19  3:24 ` [PATCH v3 02/10] crypto: ccp: Add support for displaying PSP firmware versions Mario Limonciello
2023-05-19  3:24 ` [PATCH v3 03/10] crypto: ccp: Add bootloader and TEE version offsets Mario Limonciello
2023-05-19  3:24 ` [PATCH v3 04/10] crypto: ccp: move setting PSP master to earlier in the init Mario Limonciello
2023-05-23 21:21   ` Tom Lendacky
2023-05-19  3:24 ` [PATCH v3 05/10] crypto: ccp: Add support for fetching a nonce for dynamic boost control Mario Limonciello
2023-05-19  3:24 ` [PATCH v3 06/10] crypto: ccp: Add support for setting user ID " Mario Limonciello
2023-05-19  3:24 ` [PATCH v3 07/10] crypto: ccp: Add support for getting and setting DBC parameters Mario Limonciello
2023-05-19  3:24 ` Mario Limonciello [this message]
2023-05-19  3:24 ` [PATCH v3 09/10] crypto: ccp: Add unit tests for dynamic boost control Mario Limonciello
2023-05-19  3:24 ` [PATCH v3 10/10] crypto: ccp: Add Mario to MAINTAINERS Mario Limonciello

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230519032448.94279-9-mario.limonciello@amd.com \
    --to=mario.limonciello@amd.com \
    --cc=davem@davemloft.net \
    --cc=herbert@gondor.apana.org.au \
    --cc=john.allen@amd.com \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=thomas.lendacky@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.