1 /* 2 * skl-sst-utils.c - SKL sst utils functions 3 * 4 * Copyright (C) 2016 Intel Corp 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as version 2, as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 */ 15 16 #include <linux/device.h> 17 #include <linux/slab.h> 18 #include <linux/uuid.h> 19 #include "skl-sst-dsp.h" 20 #include "../common/sst-dsp.h" 21 #include "../common/sst-dsp-priv.h" 22 #include "skl-sst-ipc.h" 23 24 25 #define UUID_STR_SIZE 37 26 #define DEFAULT_HASH_SHA256_LEN 32 27 28 /* FW Extended Manifest Header id = $AE1 */ 29 #define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124 30 31 struct skl_dfw_module_mod { 32 char name[100]; 33 struct skl_dfw_module skl_dfw_mod; 34 }; 35 36 struct UUID { 37 u8 id[16]; 38 }; 39 40 union seg_flags { 41 u32 ul; 42 struct { 43 u32 contents : 1; 44 u32 alloc : 1; 45 u32 load : 1; 46 u32 read_only : 1; 47 u32 code : 1; 48 u32 data : 1; 49 u32 _rsvd0 : 2; 50 u32 type : 4; 51 u32 _rsvd1 : 4; 52 u32 length : 16; 53 } r; 54 } __packed; 55 56 struct segment_desc { 57 union seg_flags flags; 58 u32 v_base_addr; 59 u32 file_offset; 60 }; 61 62 struct module_type { 63 u32 load_type : 4; 64 u32 auto_start : 1; 65 u32 domain_ll : 1; 66 u32 domain_dp : 1; 67 u32 rsvd : 25; 68 } __packed; 69 70 struct adsp_module_entry { 71 u32 struct_id; 72 u8 name[8]; 73 struct UUID uuid; 74 struct module_type type; 75 u8 hash1[DEFAULT_HASH_SHA256_LEN]; 76 u32 entry_point; 77 u16 cfg_offset; 78 u16 cfg_count; 79 u32 affinity_mask; 80 u16 instance_max_count; 81 u16 instance_bss_size; 82 struct segment_desc segments[3]; 83 } __packed; 84 85 struct adsp_fw_hdr { 86 u32 id; 87 u32 len; 88 u8 name[8]; 89 u32 preload_page_count; 90 u32 fw_image_flags; 91 u32 feature_mask; 92 u16 major; 93 u16 minor; 94 u16 hotfix; 95 u16 build; 96 u32 num_modules; 97 u32 hw_buf_base; 98 u32 hw_buf_length; 99 u32 load_offset; 100 } __packed; 101 102 struct uuid_module { 103 uuid_le uuid; 104 int id; 105 int is_loadable; 106 107 struct list_head list; 108 }; 109 110 struct skl_ext_manifest_hdr { 111 u32 id; 112 u32 len; 113 u16 version_major; 114 u16 version_minor; 115 u32 entries; 116 }; 117 118 int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, 119 struct skl_dfw_module *dfw_config) 120 { 121 struct uuid_module *module; 122 uuid_le *uuid_mod; 123 124 uuid_mod = (uuid_le *)uuid; 125 126 list_for_each_entry(module, &ctx->uuid_list, list) { 127 if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { 128 dfw_config->module_id = module->id; 129 dfw_config->is_loadable = module->is_loadable; 130 131 return 0; 132 } 133 } 134 135 return -EINVAL; 136 } 137 EXPORT_SYMBOL_GPL(snd_skl_get_module_info); 138 139 /* 140 * Parse the firmware binary to get the UUID, module id 141 * and loadable flags 142 */ 143 int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset) 144 { 145 struct adsp_fw_hdr *adsp_hdr; 146 struct adsp_module_entry *mod_entry; 147 int i, num_entry; 148 uuid_le *uuid_bin; 149 const char *buf; 150 struct skl_sst *skl = ctx->thread_context; 151 struct uuid_module *module; 152 struct firmware stripped_fw; 153 unsigned int safe_file; 154 155 /* Get the FW pointer to derive ADSP header */ 156 stripped_fw.data = ctx->fw->data; 157 stripped_fw.size = ctx->fw->size; 158 159 skl_dsp_strip_extended_manifest(&stripped_fw); 160 161 buf = stripped_fw.data; 162 163 /* check if we have enough space in file to move to header */ 164 safe_file = sizeof(*adsp_hdr) + offset; 165 if (stripped_fw.size <= safe_file) { 166 dev_err(ctx->dev, "Small fw file size, No space for hdr\n"); 167 return -EINVAL; 168 } 169 170 adsp_hdr = (struct adsp_fw_hdr *)(buf + offset); 171 172 /* check 1st module entry is in file */ 173 safe_file += adsp_hdr->len + sizeof(*mod_entry); 174 if (stripped_fw.size <= safe_file) { 175 dev_err(ctx->dev, "Small fw file size, No module entry\n"); 176 return -EINVAL; 177 } 178 179 mod_entry = (struct adsp_module_entry *) 180 (buf + offset + adsp_hdr->len); 181 182 num_entry = adsp_hdr->num_modules; 183 184 /* check all entries are in file */ 185 safe_file += num_entry * sizeof(*mod_entry); 186 if (stripped_fw.size <= safe_file) { 187 dev_err(ctx->dev, "Small fw file size, No modules\n"); 188 return -EINVAL; 189 } 190 191 192 /* 193 * Read the UUID(GUID) from FW Manifest. 194 * 195 * The 16 byte UUID format is: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX 196 * Populate the UUID table to store module_id and loadable flags 197 * for the module. 198 */ 199 200 for (i = 0; i < num_entry; i++, mod_entry++) { 201 module = kzalloc(sizeof(*module), GFP_KERNEL); 202 if (!module) 203 return -ENOMEM; 204 205 uuid_bin = (uuid_le *)mod_entry->uuid.id; 206 memcpy(&module->uuid, uuid_bin, sizeof(module->uuid)); 207 208 module->id = i; 209 module->is_loadable = mod_entry->type.load_type; 210 211 list_add_tail(&module->list, &skl->uuid_list); 212 213 dev_dbg(ctx->dev, 214 "Adding uuid :%pUL mod id: %d Loadable: %d\n", 215 &module->uuid, module->id, module->is_loadable); 216 } 217 218 return 0; 219 } 220 221 void skl_freeup_uuid_list(struct skl_sst *ctx) 222 { 223 struct uuid_module *uuid, *_uuid; 224 225 list_for_each_entry_safe(uuid, _uuid, &ctx->uuid_list, list) { 226 list_del(&uuid->list); 227 kfree(uuid); 228 } 229 } 230 231 /* 232 * some firmware binary contains some extended manifest. This needs 233 * to be stripped in that case before we load and use that image. 234 * 235 * Get the module id for the module by checking 236 * the table for the UUID for the module 237 */ 238 int skl_dsp_strip_extended_manifest(struct firmware *fw) 239 { 240 struct skl_ext_manifest_hdr *hdr; 241 242 /* check if fw file is greater than header we are looking */ 243 if (fw->size < sizeof(hdr)) { 244 pr_err("%s: Firmware file small, no hdr\n", __func__); 245 return -EINVAL; 246 } 247 248 hdr = (struct skl_ext_manifest_hdr *)fw->data; 249 250 if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) { 251 fw->size -= hdr->len; 252 fw->data += hdr->len; 253 } 254 255 return 0; 256 } 257