Skip to content

Commit

Permalink
crypto: ccp - Add a sample python script for Dynamic Boost Control
Browse files Browse the repository at this point in the history
Dynamic Boost Control commands are triggered by userspace with
an IOCTL interface that userspace will prepare proper buffers
for a request.

To allow prototyping and testing this interface, add a python3
command line script that loads the dbc_library.so for utilizing
the IOCTLs.

The signature to use and UID are passed as arguments to this script.

Acked-by: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
  • Loading branch information
Mario Limonciello authored and Herbert Xu committed Jul 20, 2023
1 parent febe3ed commit f40d42f
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 0 deletions.
1 change: 1 addition & 0 deletions tools/crypto/ccp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__
64 changes: 64 additions & 0 deletions tools/crypto/ccp/dbc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/python3
# SPDX-License-Identifier: GPL-2.0

import ctypes
import os

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"

lib = ctypes.CDLL("./dbc_library.so", mode=ctypes.RTLD_GLOBAL)


def handle_error(code):
val = code * -1
raise OSError(val, os.strerror(val))


def get_nonce(device, signature):
if not device:
raise ValueError("Device required")
buf = ctypes.create_string_buffer(DBC_NONCE_SIZE)
ret = lib.get_nonce(device.fileno(), ctypes.byref(buf), signature)
if ret:
handle_error(ret)
return buf.value


def set_uid(device, new_uid, signature):
if not signature:
raise ValueError("Signature required")
if not new_uid:
raise ValueError("UID required")
ret = lib.set_uid(device.fileno(), new_uid, signature)
if ret:
handle_error(ret)
return True


def process_param(device, message, signature, data=None):
if not signature:
raise ValueError("Signature required")
if type(message) != tuple:
raise ValueError("Expected message tuple")
arg = ctypes.c_int(data if data else 0)
ret = lib.process_param(device.fileno(), message[0], signature, ctypes.pointer(arg))
if ret:
handle_error(ret)
return arg, signature
134 changes: 134 additions & 0 deletions tools/crypto/ccp/dbc_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/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_MIN,
"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="File containing 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="File containing 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
sig = None
uid = None
if not os.path.exists(args.device):
raise IOError("Missing device {device}".format(device=args.device))
if args.signature:
if not os.path.exists(args.signature):
raise ValueError("Invalid signature file %s" % args.signature)
with open(args.signature, "rb") as f:
sig = f.read()
if len(sig) != DBC_SIG_SIZE:
raise ValueError(
"Invalid signature length %d (expected %d)" % (len(sig), DBC_SIG_SIZE)
)
if args.uid:
if not os.path.exists(args.uid):
raise ValueError("Invalid uid file %s" % args.uid)
with open(args.uid, "rb") as f:
uid = f.read()
if len(uid) != DBC_UID_SIZE:
raise ValueError(
"Invalid UID length %d (expected %d)" % (len(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, sig)
print("Nonce: %s" % _pretty_buffer(bytes(nonce)))
except OSError as e:
pretty_error(e.errno)
elif args.command == "set-uid":
try:
result = set_uid(d, uid, sig)
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, signature = process_param(d, messages[args.message], sig)
print(
"Parameter: {par}, response signature {sig}".format(
par=param,
sig=_pretty_buffer(bytes(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, signature = process_param(d, messages[args.message], sig, data)
print(
"Parameter: {par}, response signature {sig}".format(
par=param,
sig=_pretty_buffer(bytes(signature)),
)
)
except OSError as e:
pretty_error(e.errno)

0 comments on commit f40d42f

Please sign in to comment.