projects/linux·blob master · refs

298 lines · 9.2 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
4 * Copyright (C) 2015 Linaro Ltd.
5 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
6 */
7
8#include <linux/device/devres.h>
9#include <linux/firmware/qcom/qcom_pas.h>
10#include <linux/kernel.h>
11#include <linux/module.h>
12
13#include "qcom_pas.h"
14
15static struct qcom_pas_ops *ops_ptr;
16
17/**
18 * devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
19 * context for a given peripheral
20 *
21 * PAS context is device-resource managed, so the caller does not need
22 * to worry about freeing the context memory.
23 *
24 * @dev: PAS firmware device
25 * @pas_id: peripheral authentication service id
26 * @mem_phys: Subsystem reserve memory start address
27 * @mem_size: Subsystem reserve memory size
28 *
29 * Return: The new PAS context, or ERR_PTR() on failure.
30 */
31struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
32 u32 pas_id,
33 phys_addr_t mem_phys,
34 size_t mem_size)
35{
36 struct qcom_pas_context *ctx;
37
38 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
39 if (!ctx)
40 return ERR_PTR(-ENOMEM);
41
42 ctx->dev = dev;
43 ctx->pas_id = pas_id;
44 ctx->mem_phys = mem_phys;
45 ctx->mem_size = mem_size;
46
47 return ctx;
48}
49EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
50
51/**
52 * qcom_pas_init_image() - Initialize peripheral authentication service state
53 * machine for a given peripheral, using the metadata
54 * @pas_id: peripheral authentication service id
55 * @metadata: pointer to memory containing ELF header, program header table
56 * and optional blob of data used for authenticating the metadata
57 * and the rest of the firmware
58 * @size: size of the metadata
59 * @ctx: optional pas context
60 *
61 * Return: 0 on success.
62 *
63 * Upon successful return, the PAS metadata context (@ctx) will be used to
64 * track the metadata allocation, this needs to be released by invoking
65 * qcom_pas_metadata_release() by the caller.
66 */
67int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
68 struct qcom_pas_context *ctx)
69{
70 if (!ops_ptr)
71 return -ENODEV;
72
73 return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
74}
75EXPORT_SYMBOL_GPL(qcom_pas_init_image);
76
77/**
78 * qcom_pas_metadata_release() - release metadata context
79 * @ctx: pas context
80 */
81void qcom_pas_metadata_release(struct qcom_pas_context *ctx)
82{
83 if (!ops_ptr || !ctx || !ctx->ptr)
84 return;
85
86 ops_ptr->metadata_release(ops_ptr->dev, ctx);
87}
88EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
89
90/**
91 * qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
92 * for firmware loading
93 * @pas_id: peripheral authentication service id
94 * @addr: start address of memory area to prepare
95 * @size: size of the memory area to prepare
96 *
97 * Return: 0 on success.
98 */
99int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
100{
101 if (!ops_ptr)
102 return -ENODEV;
103
104 return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);
105}
106EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
107
108/**
109 * qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
110 * for a given peripheral.
111 *
112 * Qualcomm remote processor may rely on both static and dynamic resources for
113 * its functionality. Static resources typically refer to memory-mapped
114 * addresses required by the subsystem and are often embedded within the
115 * firmware binary and dynamic resources, such as shared memory in DDR etc.,
116 * are determined at runtime during the boot process.
117 *
118 * On Qualcomm Technologies devices, it's possible that static resources are
119 * not embedded in the firmware binary and instead are provided by TrustZone.
120 * However, dynamic resources are always expected to come from TrustZone. This
121 * indicates that for Qualcomm devices, all resources (static and dynamic) will
122 * be provided by TrustZone PAS service.
123 *
124 * If the remote processor firmware binary does contain static resources, they
125 * should be passed in input_rt. These will be forwarded to TrustZone for
126 * authentication. TrustZone will then append the dynamic resources and return
127 * the complete resource table in output_rt_tzm.
128 *
129 * If the remote processor firmware binary does not include a resource table,
130 * the caller of this function should set input_rt as NULL and input_rt_size
131 * as zero respectively.
132 *
133 * More about documentation on resource table data structures can be found in
134 * include/linux/remoteproc.h
135 *
136 * @ctx: PAS context
137 * @input_rt: resource table buffer which is present in firmware binary
138 * @input_rt_size: size of the resource table present in firmware binary
139 * @output_rt_size: TrustZone expects caller should pass worst case size for
140 * the output_rt_tzm.
141 *
142 * Return:
143 * On success, returns a pointer to the allocated buffer containing the final
144 * resource table and output_rt_size will have actual resource table size from
145 * TrustZone. The caller is responsible for freeing the buffer. On failure,
146 * returns ERR_PTR(-errno).
147 */
148struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
149 void *input_rt,
150 size_t input_rt_size,
151 size_t *output_rt_size)
152{
153 if (!ops_ptr)
154 return ERR_PTR(-ENODEV);
155 if (!ctx)
156 return ERR_PTR(-EINVAL);
157
158 return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,
159 input_rt_size, output_rt_size);
160}
161EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
162
163/**
164 * qcom_pas_auth_and_reset() - Authenticate the given peripheral firmware
165 * and reset the remote processor
166 * @pas_id: peripheral authentication service id
167 *
168 * Return: 0 on success.
169 */
170int qcom_pas_auth_and_reset(u32 pas_id)
171{
172 if (!ops_ptr)
173 return -ENODEV;
174
175 return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);
176}
177EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
178
179/**
180 * qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
181 * remote processor
182 *
183 * @ctx: Context saved during call to devm_qcom_pas_context_alloc()
184 *
185 * This function performs the necessary steps to prepare a PAS subsystem,
186 * authenticate it using the provided metadata, and initiate a reset sequence.
187 *
188 * It should be used when Linux is in control setting up the IOMMU hardware
189 * for remote subsystem during secure firmware loading processes. The
190 * preparation step sets up a shmbridge over the firmware memory before
191 * TrustZone accesses the firmware memory region for authentication. The
192 * authentication step verifies the integrity and authenticity of the firmware
193 * or configuration using secure metadata. Finally, the reset step ensures the
194 * subsystem starts in a clean and sane state.
195 *
196 * Return: 0 on success, negative errno on failure.
197 */
198int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx)
199{
200 if (!ops_ptr)
201 return -ENODEV;
202 if (!ctx)
203 return -EINVAL;
204
205 return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);
206}
207EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
208
209/**
210 * qcom_pas_set_remote_state() - Set the remote processor state
211 * @state: peripheral state
212 * @pas_id: peripheral authentication service id
213 *
214 * Return: 0 on success.
215 */
216int qcom_pas_set_remote_state(u32 state, u32 pas_id)
217{
218 if (!ops_ptr)
219 return -ENODEV;
220
221 return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);
222}
223EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
224
225/**
226 * qcom_pas_shutdown() - Shut down the remote processor
227 * @pas_id: peripheral authentication service id
228 *
229 * Return: 0 on success.
230 */
231int qcom_pas_shutdown(u32 pas_id)
232{
233 if (!ops_ptr)
234 return -ENODEV;
235
236 return ops_ptr->shutdown(ops_ptr->dev, pas_id);
237}
238EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
239
240/**
241 * qcom_pas_supported() - Check if the peripheral authentication service is
242 * supported for the given peripheral
243 * @pas_id: peripheral authentication service id
244 *
245 * Return: true if PAS is supported for this peripheral, otherwise false.
246 */
247bool qcom_pas_supported(u32 pas_id)
248{
249 if (!ops_ptr)
250 return false;
251
252 return ops_ptr->supported(ops_ptr->dev, pas_id);
253}
254EXPORT_SYMBOL_GPL(qcom_pas_supported);
255
256/**
257 * qcom_pas_is_available() - Check if the peripheral authentication service is
258 * available. Note that it is mandatory for any PAS
259 * client to invoke this API. If it returns true then
260 * only any other PAS API can be invoked.
261 *
262 * Return: true if PAS is available, otherwise false.
263 */
264bool qcom_pas_is_available(void)
265{
266 /*
267 * The barrier for ops_ptr is intended to synchronize the data stores
268 * for the ops data structure when client drivers are in parallel
269 * checking for PAS service availability.
270 *
271 * Once the PAS backend becomes available, it is allowed for multiple
272 * threads to enter TZ for parallel bringup of co-processors during
273 * boot.
274 */
275 return !!smp_load_acquire(&ops_ptr);
276}
277EXPORT_SYMBOL_GPL(qcom_pas_is_available);
278
279void qcom_pas_ops_register(struct qcom_pas_ops *ops)
280{
281 if (!qcom_pas_is_available())
282 /* Paired with smp_load_acquire() in qcom_pas_is_available() */
283 smp_store_release(&ops_ptr, ops);
284 else
285 pr_err("qcom_pas: ops already registered by %s\n",
286 ops_ptr->drv_name);
287}
288EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
289
290void qcom_pas_ops_unregister(void)
291{
292 /* Paired with smp_load_acquire() in qcom_pas_is_available() */
293 smp_store_release(&ops_ptr, NULL);
294}
295EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
296
297MODULE_LICENSE("GPL");
298MODULE_DESCRIPTION("Qualcomm generic TZ PAS driver");