Skip to content

Commit

Permalink
firmware: qcom_scm: Add support for Qualcomm Secure Execution Environ…
Browse files Browse the repository at this point in the history
…ment SCM interface

Add support for SCM calls to Secure OS and the Secure Execution
Environment (SEE) residing in the TrustZone (TZ) via the QSEECOM
interface. This allows communication with Secure/TZ applications, for
example 'uefisecapp' managing access to UEFI variables.

For better separation, make qcom_scm spin up a dedicated child
(platform) device in case QSEECOM support has been detected. The
corresponding driver for this device is then responsible for managing
any QSEECOM clients. Specifically, this driver attempts to automatically
detect known and supported applications, creating a client (auxiliary)
device for each one. The respective client/auxiliary driver is then
responsible for managing and communicating with the application.

While this patch introduces only a very basic interface without the more
advanced features (such as re-entrant and blocking SCM calls and
listeners/callbacks), this is enough to talk to the aforementioned
'uefisecapp'.

Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Reviewed-by: Johan Hovold <johan+linaro@kernel.org>
Link: https://lore.kernel.org/r/20230827211408.689076-3-luzmaximilian@gmail.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
  • Loading branch information
Maximilian Luz authored and Bjorn Andersson committed Sep 13, 2023
1 parent e4c89f9 commit 00b1248
Show file tree
Hide file tree
Showing 7 changed files with 603 additions and 0 deletions.
6 changes: 6 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -17800,6 +17800,12 @@ S: Maintained
F: Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
F: drivers/mtd/nand/raw/qcom_nandc.c

QUALCOMM QSEECOM DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: linux-arm-msm@vger.kernel.org
S: Maintained
F: drivers/firmware/qcom_qseecom.c

QUALCOMM RMNET DRIVER
M: Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
M: Sean Tranchetti <quic_stranche@quicinc.com>
Expand Down
16 changes: 16 additions & 0 deletions drivers/firmware/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,22 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT

Say Y here to enable "download mode" by default.

config QCOM_QSEECOM
bool "Qualcomm QSEECOM interface driver"
depends on QCOM_SCM=y
help
Various Qualcomm SoCs have a Secure Execution Environment (SEE) running
in the Trust Zone. This module provides an interface to that via the
QSEECOM mechanism, using SCM calls.

The QSEECOM interface allows, among other things, access to applications
running in the SEE. An example of such an application is 'uefisecapp',
which is required to access UEFI variables on certain systems. If
selected, the interface will also attempt to detect and register client
devices for supported applications.

Select Y here to enable the QSEECOM interface driver.

config SYSFB
bool
select BOOT_VESA_SUPPORT
Expand Down
1 change: 1 addition & 0 deletions drivers/firmware/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom-scm.o
qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
obj-$(CONFIG_SYSFB) += sysfb.o
obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
Expand Down
118 changes: 118 additions & 0 deletions drivers/firmware/qcom_qseecom.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for Qualcomm Secure Execution Environment (SEE) interface (QSEECOM).
* Responsible for setting up and managing QSEECOM client devices.
*
* Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <linux/auxiliary_bus.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>

#include <linux/firmware/qcom/qcom_qseecom.h>
#include <linux/firmware/qcom/qcom_scm.h>

struct qseecom_app_desc {
const char *app_name;
const char *dev_name;
};

static void qseecom_client_release(struct device *dev)
{
struct qseecom_client *client;

client = container_of(dev, struct qseecom_client, aux_dev.dev);
kfree(client);
}

static void qseecom_client_remove(void *data)
{
struct qseecom_client *client = data;

auxiliary_device_delete(&client->aux_dev);
auxiliary_device_uninit(&client->aux_dev);
}

static int qseecom_client_register(struct platform_device *qseecom_dev,
const struct qseecom_app_desc *desc)
{
struct qseecom_client *client;
u32 app_id;
int ret;

/* Try to find the app ID, skip device if not found */
ret = qcom_scm_qseecom_app_get_id(desc->app_name, &app_id);
if (ret)
return ret == -ENOENT ? 0 : ret;

dev_info(&qseecom_dev->dev, "setting up client for %s\n", desc->app_name);

/* Allocate and set-up the client device */
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return -ENOMEM;

client->aux_dev.name = desc->dev_name;
client->aux_dev.dev.parent = &qseecom_dev->dev;
client->aux_dev.dev.release = qseecom_client_release;
client->app_id = app_id;

ret = auxiliary_device_init(&client->aux_dev);
if (ret) {
kfree(client);
return ret;
}

ret = auxiliary_device_add(&client->aux_dev);
if (ret) {
auxiliary_device_uninit(&client->aux_dev);
return ret;
}

ret = devm_add_action_or_reset(&qseecom_dev->dev, qseecom_client_remove, client);
if (ret)
return ret;

return 0;
}

/*
* List of supported applications. One client device will be created per entry,
* assuming the app has already been loaded (usually by firmware bootloaders)
* and its ID can be queried successfully.
*/
static const struct qseecom_app_desc qcom_qseecom_apps[] = {};

static int qcom_qseecom_probe(struct platform_device *qseecom_dev)
{
int ret;
int i;

/* Set up client devices for each base application */
for (i = 0; i < ARRAY_SIZE(qcom_qseecom_apps); i++) {
ret = qseecom_client_register(qseecom_dev, &qcom_qseecom_apps[i]);
if (ret)
return ret;
}

return 0;
}

static struct platform_driver qcom_qseecom_driver = {
.driver = {
.name = "qcom_qseecom",
},
.probe = qcom_qseecom_probe,
};

static int __init qcom_qseecom_init(void)
{
return platform_driver_register(&qcom_qseecom_driver);
}
subsys_initcall(qcom_qseecom_init);

MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("Driver for the Qualcomm SEE (QSEECOM) interface");
MODULE_LICENSE("GPL");
Loading

0 comments on commit 00b1248

Please sign in to comment.