From: Simon Glass <sjg@chromium.org> Add a sandbox TKey driver that enables communication with physical TKey devices via serial port (/dev/ttyACM0). This allows testing TKey functionality in sandbox with real hardware. The driver: - Opens the configured device path from device tree - Configures TTY parameters using os_tty_set_params() - Implements read/write operations for TKey protocol - Supports both read() and read_all() operations Device tree configuration: tkey-test { compatible = "sandbox,tkey"; sandbox,device-path = "/dev/ttyACM0"; }; Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- arch/sandbox/dts/sandbox.dtsi | 5 + drivers/misc/Makefile | 1 + drivers/misc/tkey_sandbox.c | 170 ++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 drivers/misc/tkey_sandbox.c diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index 48e34a7aee5..e5d6be633fb 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -356,6 +356,11 @@ clock-frequency = <1000000>; }; + tkey-test { + compatible = "sandbox,tkey"; + sandbox,device-path = "/dev/ttyACM0"; + }; + tpm { compatible = "google,sandbox-tpm"; }; diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 298bc1c0a69..cd7170986ac 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_SANDBOX) += p2sb_sandbox.o p2sb_emul.o obj-$(CONFIG_SANDBOX) += swap_case.o ifdef CONFIG_SANDBOX obj-$(CONFIG_TKEY) += tkey_emul.o +obj-$(CONFIG_TKEY) += tkey_sandbox.o endif endif diff --git a/drivers/misc/tkey_sandbox.c b/drivers/misc/tkey_sandbox.c new file mode 100644 index 00000000000..9b26bd36f1b --- /dev/null +++ b/drivers/misc/tkey_sandbox.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Canonical Ltd + * + * Sandbox TKey driver for testing TKey functionality in sandbox + * Communicates with TKey devices via /dev/ttyACM0 + */ + +#define LOG_CATEGORY UCLASS_TKEY + +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <malloc.h> +#include <os.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <asm/unaligned.h> +#include <tkey.h> + +/* + * struct tkey_sandbox_priv - private information about sandbox + * + * @path: Path to the tkey device, e.g. "/dev/ttyACM0" + * @fd: File descriptor + */ +struct tkey_sandbox_priv { + char *path; + int fd; +}; + +static int tkey_sandbox_read(struct udevice *dev, void *buffer, int len, + int timeout_ms) +{ + struct tkey_sandbox_priv *priv = dev_get_priv(dev); + u8 *buf = buffer; + int total, ret; + + if (priv->fd < 0) + return -ENODEV; + + log_debug("Reading %d bytes...\n", len); + + /* Read data in chunks until we get the full amount */ + for (total = 0; total < len; total += ret) { + ret = os_read(priv->fd, buf + total, len - total); + log_debug("Read attempt returned: %d (total: %d/%d)\n", ret, + total, len); + + if (ret < 0) { + log_debug("Read failed with error %d\n", ret); + return -EIO; + } + + if (!ret) { + if (!total) { + log_debug("Read timeout - no data received\n"); + return -EIO; + } + /* Partial read - break and return what we got */ + log_debug("Partial read, got %x/%x bytes\n", total, + len); + break; + } + } + + log_debug("Read %d bytes:", total); + for (int i = 0; i < total; i++) + log_debug(" %02x", buf[i]); + log_debug("\n"); + + return total; +} + +static int tkey_sandbox_write(struct udevice *dev, const void *buffer, int len) +{ + struct tkey_sandbox_priv *priv = dev_get_priv(dev); + int ret; + + if (priv->fd < 0) + return -ENODEV; + + log_debug("Writing %d bytes:", len); + for (int i = 0; i < len; i++) + log_debug(" %02x", ((u8*)buffer)[i]); + log_debug("\n"); + + ret = os_write(priv->fd, buffer, len); + if (ret < 0) { + log_debug("Write failed with error %d\n", ret); + return -EIO; + } + log_debug("Wrote %d bytes\n", ret); + + return ret; +} + +static int tkey_sandbox_probe(struct udevice *dev) +{ + struct tkey_sandbox_priv *priv = dev_get_priv(dev); + const char *device_path; + + /* Get device path from device tree or use default */ + device_path = dev_read_string(dev, "sandbox,device-path"); + if (!device_path) + device_path = "/dev/ttyACM0"; + + priv->path = strdup(device_path); + if (!priv->path) + return -ENOMEM; + + /* Open the serial device */ + priv->fd = os_open(priv->path, OS_O_RDWR); + if (priv->fd < 0) { + log_err("Failed to open %s (error %d)\n", priv->path, priv->fd); + free(priv->path); + return -ENODEV; + } + + /* Configure serial port for raw mode */ + if (os_tty_set_params(priv->fd) < 0) { + log_err("Failed to configure serial port %s\n", priv->path); + os_close(priv->fd); + free(priv->path); + return -ENODEV; + } + log_debug("Connected to %s with serial parameters configured\n", + priv->path); + + return 0; +} + +static int tkey_sandbox_remove(struct udevice *dev) +{ + struct tkey_sandbox_priv *priv = dev_get_priv(dev); + + if (priv->fd >= 0) { + os_close(priv->fd); + priv->fd = -1; + } + + if (priv->path) { + free(priv->path); + priv->path = NULL; + } + log_debug("Disconnected\n"); + + return 0; +} + +/* TKey uclass operations */ +static const struct tkey_ops tkey_sandbox_ops = { + .read = tkey_sandbox_read, + .write = tkey_sandbox_write, +}; + +static const struct udevice_id tkey_sandbox_ids[] = { + { .compatible = "sandbox,tkey" }, + { } +}; + +U_BOOT_DRIVER(tkey_sandbox) = { + .name = "tkey_sandbox", + .id = UCLASS_TKEY, + .of_match = tkey_sandbox_ids, + .probe = tkey_sandbox_probe, + .remove = tkey_sandbox_remove, + .ops = &tkey_sandbox_ops, + .priv_auto = sizeof(struct tkey_sandbox_priv), +}; -- 2.43.0