From 2c3c1048746a4622d8c89a29670120dc8fab93c4 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:49:45 +0200 Subject: Adding upstream version 6.1.76. Signed-off-by: Daniel Baumann --- .../greybus/Documentation/firmware/authenticate.c | 94 ++++++ .../Documentation/firmware/firmware-management | 333 +++++++++++++++++++++ .../greybus/Documentation/firmware/firmware.c | 218 ++++++++++++++ 3 files changed, 645 insertions(+) create mode 100644 drivers/staging/greybus/Documentation/firmware/authenticate.c create mode 100644 drivers/staging/greybus/Documentation/firmware/firmware-management create mode 100644 drivers/staging/greybus/Documentation/firmware/firmware.c (limited to 'drivers/staging/greybus/Documentation/firmware') diff --git a/drivers/staging/greybus/Documentation/firmware/authenticate.c b/drivers/staging/greybus/Documentation/firmware/authenticate.c new file mode 100644 index 000000000..3d2c6f88a --- /dev/null +++ b/drivers/staging/greybus/Documentation/firmware/authenticate.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Sample code to test CAP protocol + * + * Copyright(c) 2016 Google Inc. All rights reserved. + * Copyright(c) 2016 Linaro Ltd. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "../../greybus_authentication.h" + +struct cap_ioc_get_endpoint_uid uid; +struct cap_ioc_get_ims_certificate cert = { + .certificate_class = 0, + .certificate_id = 0, +}; + +struct cap_ioc_authenticate authenticate = { + .auth_type = 0, + .challenge = {0}, +}; + +int main(int argc, char *argv[]) +{ + unsigned int timeout = 10000; + char *capdev; + int fd, ret; + + /* Make sure arguments are correct */ + if (argc != 2) { + printf("\nUsage: ./firmware \n"); + return 0; + } + + capdev = argv[1]; + + printf("Opening %s authentication device\n", capdev); + + fd = open(capdev, O_RDWR); + if (fd < 0) { + printf("Failed to open: %s\n", capdev); + return -1; + } + + /* Get UID */ + printf("Get UID\n"); + + ret = ioctl(fd, CAP_IOC_GET_ENDPOINT_UID, &uid); + if (ret < 0) { + printf("Failed to get UID: %s (%d)\n", capdev, ret); + ret = -1; + goto close_fd; + } + + printf("UID received: 0x%llx\n", *(unsigned long long int *)(uid.uid)); + + /* Get certificate */ + printf("Get IMS certificate\n"); + + ret = ioctl(fd, CAP_IOC_GET_IMS_CERTIFICATE, &cert); + if (ret < 0) { + printf("Failed to get IMS certificate: %s (%d)\n", capdev, ret); + ret = -1; + goto close_fd; + } + + printf("IMS Certificate size: %d\n", cert.cert_size); + + /* Authenticate */ + printf("Authenticate module\n"); + + memcpy(authenticate.uid, uid.uid, 8); + + ret = ioctl(fd, CAP_IOC_AUTHENTICATE, &authenticate); + if (ret < 0) { + printf("Failed to authenticate module: %s (%d)\n", capdev, ret); + ret = -1; + goto close_fd; + } + + printf("Authenticated, result (%02x), sig-size (%02x)\n", + authenticate.result_code, authenticate.signature_size); + +close_fd: + close(fd); + + return ret; +} diff --git a/drivers/staging/greybus/Documentation/firmware/firmware-management b/drivers/staging/greybus/Documentation/firmware/firmware-management new file mode 100644 index 000000000..7918257e5 --- /dev/null +++ b/drivers/staging/greybus/Documentation/firmware/firmware-management @@ -0,0 +1,333 @@ + +Firmware Management +------------------- + Copyright 2016 Google Inc. + Copyright 2016 Linaro Ltd. + +Interface-Manifest +------------------ + +All firmware packages on the Modules or Interfaces are managed by a special +Firmware Management Protocol. To support Firmware Management by the AP, the +Interface Manifest shall at least contain the Firmware Management Bundle and a +Firmware Management Protocol CPort within it. + +The bundle may contain additional CPorts based on the extra functionality +required to manage firmware packages. + +For example, this is how the Firmware Management part of the Interface Manifest +may look like: + + ; Firmware Management Bundle (Bundle 1): + [bundle-descriptor 1] + class = 0x16 + + ; (Mandatory) Firmware Management Protocol on CPort 1 + [cport-descriptor 2] + bundle = 1 + protocol = 0x18 + + ; (Optional) Firmware Download Protocol on CPort 2 + [cport-descriptor 1] + bundle = 1 + protocol = 0x17 + + ; (Optional) SPI protocol on CPort 3 + [cport-descriptor 3] + bundle = 1 + protocol = 0x0b + + ; (Optional) Component Authentication Protocol (CAP) on CPort 4 + [cport-descriptor 4] + bundle = 1 + protocol = 0x19 + + +Sysfs Interfaces - Firmware Management +-------------------------------------- + +The Firmware Management Protocol interacts with Userspace using the character +device interface. The character device will be present in /dev/ directory +and will be named gb-fw-mgmt-. The number is assigned at runtime. + +Identifying the Character Device +================================ + +There can be multiple devices present in /dev/ directory with name gb-fw-mgmt-N +and user first needs to identify the character device used for +firmware-management for a particular interface. + +The Firmware Management core creates a device of class 'gb_fw_mgmt', which shall +be used by the user to identify the right character device for it. The class +device is created within the Bundle directory for a particular Interface. + +For example this is how the class-device can be present: + +/sys/bus/greybus/devices/1-1/1-1.1/1-1.1.1/gb_fw_mgmt/gb-fw-mgmt-0 + +The last name in this path: gb-fw-mgmt-0 is precisely the name of the char +device and so the device in this case will be: + +/dev/gb-fw-mgmt-0. + +Operations on the Char device +============================= + +The Character device (gb-fw-mgmt-0 in example) can be opened by the userspace +application and it can perform various 'ioctl' operations on the device. The +device doesn't support any read/write operations. + +Following are the IOCTLs and their data structures available to the user: + +/* IOCTL support */ +#define GB_FW_LOAD_METHOD_UNIPRO 0x01 +#define GB_FW_LOAD_METHOD_INTERNAL 0x02 + +#define GB_FW_LOAD_STATUS_FAILED 0x00 +#define GB_FW_LOAD_STATUS_UNVALIDATED 0x01 +#define GB_FW_LOAD_STATUS_VALIDATED 0x02 +#define GB_FW_LOAD_STATUS_VALIDATION_FAILED 0x03 + +#define GB_FW_BACKEND_FW_STATUS_SUCCESS 0x01 +#define GB_FW_BACKEND_FW_STATUS_FAIL_FIND 0x02 +#define GB_FW_BACKEND_FW_STATUS_FAIL_FETCH 0x03 +#define GB_FW_BACKEND_FW_STATUS_FAIL_WRITE 0x04 +#define GB_FW_BACKEND_FW_STATUS_INT 0x05 +#define GB_FW_BACKEND_FW_STATUS_RETRY 0x06 +#define GB_FW_BACKEND_FW_STATUS_NOT_SUPPORTED 0x07 + +#define GB_FW_BACKEND_VERSION_STATUS_SUCCESS 0x01 +#define GB_FW_BACKEND_VERSION_STATUS_NOT_AVAILABLE 0x02 +#define GB_FW_BACKEND_VERSION_STATUS_NOT_SUPPORTED 0x03 +#define GB_FW_BACKEND_VERSION_STATUS_RETRY 0x04 +#define GB_FW_BACKEND_VERSION_STATUS_FAIL_INT 0x05 + + +struct fw_mgmt_ioc_get_intf_version { + __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE]; + __u16 major; + __u16 minor; +} __attribute__ ((__packed__)); + +struct fw_mgmt_ioc_get_backend_version { + __u8 firmware_tag[GB_FIRMWARE_U_TAG_MAX_SIZE]; + __u16 major; + __u16 minor; + __u8 status; +} __attribute__ ((__packed__)); + +struct fw_mgmt_ioc_intf_load_and_validate { + __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE]; + __u8 load_method; + __u8 status; + __u16 major; + __u16 minor; +} __packed; + +struct fw_mgmt_ioc_backend_fw_update { + __u8 firmware_tag[GB_FIRMWARE_TAG_MAX_SIZE]; + __u8 status; +} __packed; + +#define FW_MGMT_IOCTL_BASE 'S' +#define FW_MGMT_IOC_GET_INTF_FW _IOR(FW_MGMT_IOCTL_BASE, 0, struct fw_mgmt_ioc_get_intf_version) +#define FW_MGMT_IOC_GET_BACKEND_FW _IOWR(FW_MGMT_IOCTL_BASE, 1, struct fw_mgmt_ioc_get_backend_version) +#define FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE _IOWR(FW_MGMT_IOCTL_BASE, 2, struct fw_mgmt_ioc_intf_load_and_validate) +#define FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE _IOWR(FW_MGMT_IOCTL_BASE, 3, struct fw_mgmt_ioc_backend_fw_update) +#define FW_MGMT_IOC_SET_TIMEOUT_MS _IOW(FW_MGMT_IOCTL_BASE, 4, unsigned int) +#define FW_MGMT_IOC_MODE_SWITCH _IO(FW_MGMT_IOCTL_BASE, 5) + +1. FW_MGMT_IOC_GET_INTF_FW: + + This ioctl shall be used by the user to get the version and firmware-tag of + the currently running Interface Firmware. All the fields of the 'struct + fw_mgmt_ioc_get_fw' are filled by the kernel. + +2. FW_MGMT_IOC_GET_BACKEND_FW: + + This ioctl shall be used by the user to get the version of a currently + running Backend Interface Firmware identified by a firmware-tag. The user is + required to fill the 'firmware_tag' field of the 'struct fw_mgmt_ioc_get_fw' + in this case. The 'major' and 'minor' fields are set by the kernel in + response. + +3. FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE: + + This ioctl shall be used by the user to load an Interface Firmware package on + an Interface. The user needs to fill the 'firmware_tag' and 'load_method' + fields of the 'struct fw_mgmt_ioc_intf_load_and_validate'. The 'status', + 'major' and 'minor' fields are set by the kernel in response. + +4. FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE: + + This ioctl shall be used by the user to request an Interface to update a + Backend Interface Firmware. The user is required to fill the 'firmware_tag' + field of the 'struct fw_mgmt_ioc_get_fw' in this case. The 'status' field is + set by the kernel in response. + +5. FW_MGMT_IOC_SET_TIMEOUT_MS: + + This ioctl shall be used by the user to increase the timeout interval within + which the firmware must get loaded by the Module. The default timeout is 1 + second. The user needs to pass the timeout in milliseconds. + +6. FW_MGMT_IOC_MODE_SWITCH: + + This ioctl shall be used by the user to mode-switch the module to the + previously loaded interface firmware. If the interface firmware isn't loaded + previously, or if another unsuccessful FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE + operation is started after loading interface firmware, then the firmware core + wouldn't allow mode-switch. + + +Sysfs Interfaces - Authentication +--------------------------------- + +The Component Authentication Protocol interacts with Userspace using the +character device interface. The character device will be present in /dev/ +directory and will be named gb-authenticate-. The number is assigned at +runtime. + +Identifying the Character Device +================================ + +There can be multiple devices present in /dev/ directory with name +gb-authenticate-N and user first needs to identify the character device used for +authentication a of particular interface. + +The Authentication core creates a device of class 'gb_authenticate', which shall +be used by the user to identify the right character device for it. The class +device is created within the Bundle directory for a particular Interface. + +For example this is how the class-device can be present: + +/sys/bus/greybus/devices/1-1/1-1.1/1-1.1.1/gb_authenticate/gb-authenticate-0 + +The last name in this path: gb-authenticate-0 is precisely the name of the char +device and so the device in this case will be: + +/dev/gb-authenticate-0. + +Operations on the Char device +============================= + +The Character device (/dev/gb-authenticate-0 in above example) can be opened by +the userspace application and it can perform various 'ioctl' operations on the +device. The device doesn't support any read/write operations. + +Following are the IOCTLs and their data structures available to the user: + +#define CAP_CERTIFICATE_MAX_SIZE 1600 +#define CAP_SIGNATURE_MAX_SIZE 320 + +/* Certificate class types */ +#define CAP_CERT_IMS_EAPC 0x00000001 +#define CAP_CERT_IMS_EASC 0x00000002 +#define CAP_CERT_IMS_EARC 0x00000003 +#define CAP_CERT_IMS_IAPC 0x00000004 +#define CAP_CERT_IMS_IASC 0x00000005 +#define CAP_CERT_IMS_IARC 0x00000006 + +/* IMS Certificate response result codes */ +#define CAP_IMS_RESULT_CERT_FOUND 0x00 +#define CAP_IMS_RESULT_CERT_CLASS_INVAL 0x01 +#define CAP_IMS_RESULT_CERT_CORRUPT 0x02 +#define CAP_IMS_RESULT_CERT_NOT_FOUND 0x03 + +/* Authentication types */ +#define CAP_AUTH_IMS_PRI 0x00000001 +#define CAP_AUTH_IMS_SEC 0x00000002 +#define CAP_AUTH_IMS_RSA 0x00000003 + +/* Authenticate response result codes */ +#define CAP_AUTH_RESULT_CR_SUCCESS 0x00 +#define CAP_AUTH_RESULT_CR_BAD_TYPE 0x01 +#define CAP_AUTH_RESULT_CR_WRONG_EP 0x02 +#define CAP_AUTH_RESULT_CR_NO_KEY 0x03 +#define CAP_AUTH_RESULT_CR_SIG_FAIL 0x04 + + +/* IOCTL support */ +struct cap_ioc_get_endpoint_uid { + __u8 uid[8]; +} __attribute__ ((__packed__)); + +struct cap_ioc_get_ims_certificate { + __u32 certificate_class; + __u32 certificate_id; + + __u8 result_code; + __u32 cert_size; + __u8 certificate[CAP_CERTIFICATE_MAX_SIZE]; +} __attribute__ ((__packed__)); + +struct cap_ioc_authenticate { + __u32 auth_type; + __u8 uid[8]; + __u8 challenge[32]; + + __u8 result_code; + __u8 response[64]; + __u32 signature_size; + __u8 signature[CAP_SIGNATURE_MAX_SIZE]; +} __attribute__ ((__packed__)); + +#define CAP_IOCTL_BASE 'C' +#define CAP_IOC_GET_ENDPOINT_UID _IOR(CAP_IOCTL_BASE, 0, struct cap_ioc_get_endpoint_uid) +#define CAP_IOC_GET_IMS_CERTIFICATE _IOWR(CAP_IOCTL_BASE, 1, struct cap_ioc_get_ims_certificate) +#define CAP_IOC_AUTHENTICATE _IOWR(CAP_IOCTL_BASE, 2, struct cap_ioc_authenticate) + + +1. CAP_IOC_GET_ENDPOINT_UID: + + This ioctl shall be used by the user to get the endpoint UID associated with + the Interface. All the fields of the 'struct cap_ioc_get_endpoint_uid' are + filled by the kernel. + +2. CAP_IOC_GET_IMS_CERTIFICATE: + + This ioctl shall be used by the user to retrieve one of the available + cryptographic certificates held by the Interface for use in Component + Authentication. The user is required to fill the 'certificate_class' and + 'certificate_id' field of the 'struct cap_ioc_get_ims_certificate' in this + case. The other fields will be set by the kernel in response. The first + 'cert_size' bytes of the 'certificate' shall be read by the user and others + must be discarded. + +3. CAP_IOC_AUTHENTICATE: + + This ioctl shall be used by the user to authenticate the Module attached to + an Interface. The user needs to fill the 'auth_type', 'uid', and 'challenge' + fields of the 'struct cap_ioc_authenticate'. The other fields will be set by + the kernel in response. The first 'signature_size' bytes of the 'signature' + shall be read by the user and others must be discarded. + + +Sysfs Interfaces - Firmware Download +------------------------------------ + +The Firmware Download Protocol uses the existing Linux Kernel's Firmware class +and the interface provided to userspace are described in: +Documentation/firmware_class/. + + +Sysfs Interfaces - SPI Flash +---------------------------- + +The SPI flash is exposed in userspace as a MTD device and is created +within the Bundle directory. For example, this is how the path may look like: + +$ ls /sys/bus/greybus/devices/1-1/1-1.1/1-1.1.1/spi_master/spi32766/spi32766.0/mtd +mtd0 mtd0ro + + +Sample Applications +------------------- + +The current directory also provides a firmware.c test application, which can be +referenced while developing userspace application to talk to firmware-management +protocol. + +The current directory also provides a authenticate.c test application, which can +be referenced while developing userspace application to talk to +component authentication protocol. diff --git a/drivers/staging/greybus/Documentation/firmware/firmware.c b/drivers/staging/greybus/Documentation/firmware/firmware.c new file mode 100644 index 000000000..765d69faa --- /dev/null +++ b/drivers/staging/greybus/Documentation/firmware/firmware.c @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * Sample code to test firmware-management protocol + * + * Copyright(c) 2016 Google Inc. All rights reserved. + * Copyright(c) 2016 Linaro Ltd. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../../greybus_firmware.h" + +#define FW_DEV_DEFAULT "/dev/gb-fw-mgmt-0" +#define FW_TAG_INT_DEFAULT "s3f" +#define FW_TAG_BCND_DEFAULT "bf_01" +#define FW_UPDATE_TYPE_DEFAULT 0 +#define FW_TIMEOUT_DEFAULT 10000 + +static const char *firmware_tag; +static const char *fwdev = FW_DEV_DEFAULT; +static unsigned int fw_update_type = FW_UPDATE_TYPE_DEFAULT; +static unsigned int fw_timeout = FW_TIMEOUT_DEFAULT; + +static struct fw_mgmt_ioc_get_intf_version intf_fw_info; +static struct fw_mgmt_ioc_get_backend_version backend_fw_info; +static struct fw_mgmt_ioc_intf_load_and_validate intf_load; +static struct fw_mgmt_ioc_backend_fw_update backend_update; + +static void usage(void) +{ + printf("\nUsage: ./firmware (default: \"s3f\"/\"bf_01\") \n"); +} + +static int update_intf_firmware(int fd) +{ + int ret; + + /* Get Interface Firmware Version */ + printf("Get Interface Firmware Version\n"); + + ret = ioctl(fd, FW_MGMT_IOC_GET_INTF_FW, &intf_fw_info); + if (ret < 0) { + printf("Failed to get interface firmware version: %s (%d)\n", + fwdev, ret); + return -1; + } + + printf("Interface Firmware tag (%s), major (%d), minor (%d)\n", + intf_fw_info.firmware_tag, intf_fw_info.major, + intf_fw_info.minor); + + /* Try Interface Firmware load over Unipro */ + printf("Loading Interface Firmware\n"); + + intf_load.load_method = GB_FW_U_LOAD_METHOD_UNIPRO; + intf_load.status = 0; + intf_load.major = 0; + intf_load.minor = 0; + + strncpy((char *)&intf_load.firmware_tag, firmware_tag, + GB_FIRMWARE_U_TAG_MAX_SIZE); + + ret = ioctl(fd, FW_MGMT_IOC_INTF_LOAD_AND_VALIDATE, &intf_load); + if (ret < 0) { + printf("Failed to load interface firmware: %s (%d)\n", fwdev, + ret); + return -1; + } + + if (intf_load.status != GB_FW_U_LOAD_STATUS_VALIDATED && + intf_load.status != GB_FW_U_LOAD_STATUS_UNVALIDATED) { + printf("Load status says loading failed: %d\n", + intf_load.status); + return -1; + } + + printf("Interface Firmware (%s) Load done: major: %d, minor: %d, status: %d\n", + firmware_tag, intf_load.major, intf_load.minor, + intf_load.status); + + /* Initiate Mode-switch to the newly loaded firmware */ + printf("Initiate Mode switch\n"); + + ret = ioctl(fd, FW_MGMT_IOC_MODE_SWITCH); + if (ret < 0) + printf("Failed to initiate mode-switch (%d)\n", ret); + + return ret; +} + +static int update_backend_firmware(int fd) +{ + int ret; + + /* Get Backend Firmware Version */ + printf("Getting Backend Firmware Version\n"); + + strncpy((char *)&backend_fw_info.firmware_tag, firmware_tag, + GB_FIRMWARE_U_TAG_MAX_SIZE); + +retry_fw_version: + ret = ioctl(fd, FW_MGMT_IOC_GET_BACKEND_FW, &backend_fw_info); + if (ret < 0) { + printf("Failed to get backend firmware version: %s (%d)\n", + fwdev, ret); + return -1; + } + + printf("Backend Firmware tag (%s), major (%d), minor (%d), status (%d)\n", + backend_fw_info.firmware_tag, backend_fw_info.major, + backend_fw_info.minor, backend_fw_info.status); + + if (backend_fw_info.status == GB_FW_U_BACKEND_VERSION_STATUS_RETRY) + goto retry_fw_version; + + if ((backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_SUCCESS) + && (backend_fw_info.status != GB_FW_U_BACKEND_VERSION_STATUS_NOT_AVAILABLE)) { + printf("Failed to get backend firmware version: %s (%d)\n", + fwdev, backend_fw_info.status); + return -1; + } + + /* Try Backend Firmware Update over Unipro */ + printf("Updating Backend Firmware\n"); + + strncpy((char *)&backend_update.firmware_tag, firmware_tag, + GB_FIRMWARE_U_TAG_MAX_SIZE); + +retry_fw_update: + backend_update.status = 0; + + ret = ioctl(fd, FW_MGMT_IOC_INTF_BACKEND_FW_UPDATE, &backend_update); + if (ret < 0) { + printf("Failed to load backend firmware: %s (%d)\n", fwdev, ret); + return -1; + } + + if (backend_update.status == GB_FW_U_BACKEND_FW_STATUS_RETRY) { + printf("Retrying firmware update: %d\n", backend_update.status); + goto retry_fw_update; + } + + if (backend_update.status != GB_FW_U_BACKEND_FW_STATUS_SUCCESS) { + printf("Load status says loading failed: %d\n", + backend_update.status); + } else { + printf("Backend Firmware (%s) Load done: status: %d\n", + firmware_tag, backend_update.status); + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int fd, ret; + char *endptr; + + if (argc > 1 && + (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) { + usage(); + return -1; + } + + if (argc > 1) + fwdev = argv[1]; + + if (argc > 2) + fw_update_type = strtoul(argv[2], &endptr, 10); + + if (argc > 3) + firmware_tag = argv[3]; + else if (!fw_update_type) + firmware_tag = FW_TAG_INT_DEFAULT; + else + firmware_tag = FW_TAG_BCND_DEFAULT; + + if (argc > 4) + fw_timeout = strtoul(argv[4], &endptr, 10); + + printf("Trying Firmware update: fwdev: %s, type: %s, tag: %s, timeout: %u\n", + fwdev, fw_update_type == 0 ? "interface" : "backend", + firmware_tag, fw_timeout); + + printf("Opening %s firmware management device\n", fwdev); + + fd = open(fwdev, O_RDWR); + if (fd < 0) { + printf("Failed to open: %s\n", fwdev); + return -1; + } + + /* Set Timeout */ + printf("Setting timeout to %u ms\n", fw_timeout); + + ret = ioctl(fd, FW_MGMT_IOC_SET_TIMEOUT_MS, &fw_timeout); + if (ret < 0) { + printf("Failed to set timeout: %s (%d)\n", fwdev, ret); + ret = -1; + goto close_fd; + } + + if (!fw_update_type) + ret = update_intf_firmware(fd); + else + ret = update_backend_firmware(fd); + +close_fd: + close(fd); + + return ret; +} -- cgit v1.2.3