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 15 static 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 */ 31 struct 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 } 49 EXPORT_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 */ 67 int 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 } 75 EXPORT_SYMBOL_GPL(qcom_pas_init_image); 76 77 /** 78 * qcom_pas_metadata_release() - release metadata context 79 * @ctx: pas context 80 */ 81 void 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 } 88 EXPORT_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 */ 99 int 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 } 106 EXPORT_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 */ 148 struct 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 } 161 EXPORT_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 */ 170 int 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 } 177 EXPORT_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 */ 198 int 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 } 207 EXPORT_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 */ 216 int 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 } 223 EXPORT_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 */ 231 int 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 } 238 EXPORT_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 */ 247 bool 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 } 254 EXPORT_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 */ 264 bool 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 } 277 EXPORT_SYMBOL_GPL(qcom_pas_is_available); 278 279 void 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 } 288 EXPORT_SYMBOL_GPL(qcom_pas_ops_register); 289 290 void 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 } 295 EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister); 296 297 MODULE_LICENSE("GPL"); 298 MODULE_DESCRIPTION("Qualcomm generic TZ PAS driver"); 299