1*d310239dSOlivier Deprez /* 2*d310239dSOlivier Deprez * Copyright (c) 2019, Arm Limited. All rights reserved. 3*d310239dSOlivier Deprez * 4*d310239dSOlivier Deprez * SPDX-License-Identifier: BSD-3-Clause 5*d310239dSOlivier Deprez */ 6*d310239dSOlivier Deprez 7*d310239dSOlivier Deprez #include <assert.h> 8*d310239dSOlivier Deprez #include <lib/debugfs.h> 9*d310239dSOlivier Deprez #include <limits.h> 10*d310239dSOlivier Deprez #include <plat/arm/common/plat_arm.h> 11*d310239dSOlivier Deprez #include <stdlib.h> 12*d310239dSOlivier Deprez #include <string.h> 13*d310239dSOlivier Deprez #include <tools_share/firmware_image_package.h> 14*d310239dSOlivier Deprez 15*d310239dSOlivier Deprez #include "dev.h" 16*d310239dSOlivier Deprez 17*d310239dSOlivier Deprez #define NR_FIPS 1 18*d310239dSOlivier Deprez #define STOC_HEADER (sizeof(fip_toc_header_t)) 19*d310239dSOlivier Deprez #define STOC_ENTRY (sizeof(fip_toc_entry_t)) 20*d310239dSOlivier Deprez 21*d310239dSOlivier Deprez struct fipfile { 22*d310239dSOlivier Deprez chan_t *c; 23*d310239dSOlivier Deprez long offset[NR_FILES]; 24*d310239dSOlivier Deprez long size[NR_FILES]; 25*d310239dSOlivier Deprez }; 26*d310239dSOlivier Deprez 27*d310239dSOlivier Deprez struct fip_entry { 28*d310239dSOlivier Deprez uuid_t uuid; 29*d310239dSOlivier Deprez long long offset_address; 30*d310239dSOlivier Deprez long long size; 31*d310239dSOlivier Deprez long long flags; 32*d310239dSOlivier Deprez }; 33*d310239dSOlivier Deprez 34*d310239dSOlivier Deprez struct uuidnames { 35*d310239dSOlivier Deprez const char name[NAMELEN]; 36*d310239dSOlivier Deprez const uuid_t uuid; 37*d310239dSOlivier Deprez }; 38*d310239dSOlivier Deprez 39*d310239dSOlivier Deprez /******************************************************************************* 40*d310239dSOlivier Deprez * This array links the FIP file names to their UUID. 41*d310239dSOlivier Deprez * The elements are ordered according to the image number stored in 42*d310239dSOlivier Deprez * tbbr_img_def.h, starting at index 1. 43*d310239dSOlivier Deprez * 44*d310239dSOlivier Deprez * TODO: this name to uuid binding will preferably be done using 45*d310239dSOlivier Deprez * the coming Property Access Layer / Firmware CONFiguration feature. 46*d310239dSOlivier Deprez ******************************************************************************/ 47*d310239dSOlivier Deprez static const struct uuidnames uuidnames[] = { 48*d310239dSOlivier Deprez {"", { {0}, {0}, {0}, 0, 0, {0} } }, 49*d310239dSOlivier Deprez {"bl2.bin", UUID_TRUSTED_BOOT_FIRMWARE_BL2}, 50*d310239dSOlivier Deprez {"scp-bl2.bin", UUID_SCP_FIRMWARE_SCP_BL2}, 51*d310239dSOlivier Deprez {"bl31.bin", UUID_EL3_RUNTIME_FIRMWARE_BL31}, 52*d310239dSOlivier Deprez {"bl32.bin", UUID_SECURE_PAYLOAD_BL32}, 53*d310239dSOlivier Deprez {"bl33.bin", UUID_NON_TRUSTED_FIRMWARE_BL33}, 54*d310239dSOlivier Deprez {"tb-fw.crt", UUID_TRUSTED_BOOT_FW_CERT}, 55*d310239dSOlivier Deprez {"trstd-k.crt", UUID_TRUSTED_KEY_CERT}, 56*d310239dSOlivier Deprez {"scp-fw-k.crt", UUID_SCP_FW_KEY_CERT}, 57*d310239dSOlivier Deprez {"soc-fw-k.crt", UUID_SOC_FW_KEY_CERT}, 58*d310239dSOlivier Deprez {"tos-fw-k.crt", UUID_TRUSTED_OS_FW_KEY_CERT}, 59*d310239dSOlivier Deprez {"nt-fw-k.crt", UUID_NON_TRUSTED_FW_KEY_CERT}, 60*d310239dSOlivier Deprez {"scp-fw-c.crt", UUID_SCP_FW_CONTENT_CERT}, 61*d310239dSOlivier Deprez {"soc-fw-c.crt", UUID_SOC_FW_CONTENT_CERT}, 62*d310239dSOlivier Deprez {"tos-fw-c.crt", UUID_TRUSTED_OS_FW_CONTENT_CERT}, 63*d310239dSOlivier Deprez {"nt-fw-c.crt", UUID_NON_TRUSTED_FW_CONTENT_CERT}, 64*d310239dSOlivier Deprez { }, 65*d310239dSOlivier Deprez {"fwu.crt", UUID_TRUSTED_FWU_CERT}, 66*d310239dSOlivier Deprez {"scp-bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U}, 67*d310239dSOlivier Deprez {"bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U}, 68*d310239dSOlivier Deprez {"ns-bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U}, 69*d310239dSOlivier Deprez {"bl32-xtr1.bin", UUID_SECURE_PAYLOAD_BL32_EXTRA1}, 70*d310239dSOlivier Deprez {"bl32-xtr2.bin", UUID_SECURE_PAYLOAD_BL32_EXTRA2}, 71*d310239dSOlivier Deprez {"hw.cfg", UUID_HW_CONFIG}, 72*d310239dSOlivier Deprez {"tb-fw.cfg", UUID_TB_FW_CONFIG}, 73*d310239dSOlivier Deprez {"soc-fw.cfg", UUID_SOC_FW_CONFIG}, 74*d310239dSOlivier Deprez {"tos-fw.cfg", UUID_TOS_FW_CONFIG}, 75*d310239dSOlivier Deprez {"nt-fw.cfg", UUID_NT_FW_CONFIG}, 76*d310239dSOlivier Deprez {"rot-k.crt", UUID_ROT_KEY_CERT}, 77*d310239dSOlivier Deprez {"nt-k.crt", UUID_NON_TRUSTED_WORLD_KEY_CERT} 78*d310239dSOlivier Deprez }; 79*d310239dSOlivier Deprez 80*d310239dSOlivier Deprez /******************************************************************************* 81*d310239dSOlivier Deprez * This array contains all the available FIP files. 82*d310239dSOlivier Deprez ******************************************************************************/ 83*d310239dSOlivier Deprez static struct fipfile archives[NR_FIPS]; 84*d310239dSOlivier Deprez 85*d310239dSOlivier Deprez /******************************************************************************* 86*d310239dSOlivier Deprez * This variable stores the current number of registered FIP files. 87*d310239dSOlivier Deprez ******************************************************************************/ 88*d310239dSOlivier Deprez static int nfips; 89*d310239dSOlivier Deprez 90*d310239dSOlivier Deprez /******************************************************************************* 91*d310239dSOlivier Deprez * This function parses the ToC of the FIP. 92*d310239dSOlivier Deprez ******************************************************************************/ 93*d310239dSOlivier Deprez static int get_entry(chan_t *c, struct fip_entry *entry) 94*d310239dSOlivier Deprez { 95*d310239dSOlivier Deprez int n; 96*d310239dSOlivier Deprez 97*d310239dSOlivier Deprez n = devtab[c->index]->read(c, entry, sizeof(struct fip_entry)); 98*d310239dSOlivier Deprez if (n <= 0) { 99*d310239dSOlivier Deprez return n; 100*d310239dSOlivier Deprez } 101*d310239dSOlivier Deprez 102*d310239dSOlivier Deprez if (n != sizeof(struct fip_entry)) { 103*d310239dSOlivier Deprez return -1; 104*d310239dSOlivier Deprez } 105*d310239dSOlivier Deprez 106*d310239dSOlivier Deprez if ((entry->size > LONG_MAX) || (entry->offset_address > LONG_MAX)) { 107*d310239dSOlivier Deprez return -1; 108*d310239dSOlivier Deprez } 109*d310239dSOlivier Deprez 110*d310239dSOlivier Deprez if (entry->size == 0) { 111*d310239dSOlivier Deprez return 0; 112*d310239dSOlivier Deprez } 113*d310239dSOlivier Deprez 114*d310239dSOlivier Deprez return 1; 115*d310239dSOlivier Deprez } 116*d310239dSOlivier Deprez 117*d310239dSOlivier Deprez /******************************************************************************* 118*d310239dSOlivier Deprez * This function exposes the FIP images as files. 119*d310239dSOlivier Deprez ******************************************************************************/ 120*d310239dSOlivier Deprez static int fipgen(chan_t *c, const dirtab_t *tab, int ntab, int n, dir_t *dir) 121*d310239dSOlivier Deprez { 122*d310239dSOlivier Deprez int i, r; 123*d310239dSOlivier Deprez long off; 124*d310239dSOlivier Deprez chan_t nc; 125*d310239dSOlivier Deprez struct fip_entry entry; 126*d310239dSOlivier Deprez struct fipfile *fip; 127*d310239dSOlivier Deprez static const char unk[] = "unknown"; 128*d310239dSOlivier Deprez 129*d310239dSOlivier Deprez if (c->dev >= nfips) { 130*d310239dSOlivier Deprez panic(); 131*d310239dSOlivier Deprez } 132*d310239dSOlivier Deprez 133*d310239dSOlivier Deprez clone(archives[c->dev].c, &nc); 134*d310239dSOlivier Deprez fip = &archives[nc.dev]; 135*d310239dSOlivier Deprez 136*d310239dSOlivier Deprez off = STOC_HEADER; 137*d310239dSOlivier Deprez for (i = 0; i <= n; i++) { 138*d310239dSOlivier Deprez if (fip->offset[i] == -1) { 139*d310239dSOlivier Deprez return 0; 140*d310239dSOlivier Deprez } 141*d310239dSOlivier Deprez 142*d310239dSOlivier Deprez if (devtab[nc.index]->seek(&nc, off, KSEEK_SET) < 0) { 143*d310239dSOlivier Deprez return -1; 144*d310239dSOlivier Deprez } 145*d310239dSOlivier Deprez 146*d310239dSOlivier Deprez r = get_entry(&nc, &entry); 147*d310239dSOlivier Deprez if (r <= 0) { 148*d310239dSOlivier Deprez return r; 149*d310239dSOlivier Deprez } 150*d310239dSOlivier Deprez 151*d310239dSOlivier Deprez off += sizeof(entry); 152*d310239dSOlivier Deprez } 153*d310239dSOlivier Deprez 154*d310239dSOlivier Deprez for (i = 1; i < NELEM(uuidnames); i++) { 155*d310239dSOlivier Deprez if (memcmp(&uuidnames[i].uuid, 156*d310239dSOlivier Deprez &entry.uuid, sizeof(uuid_t)) == 0) { 157*d310239dSOlivier Deprez break; 158*d310239dSOlivier Deprez } 159*d310239dSOlivier Deprez } 160*d310239dSOlivier Deprez 161*d310239dSOlivier Deprez if (i < NELEM(uuidnames)) { 162*d310239dSOlivier Deprez make_dir_entry(c, dir, uuidnames[i].name, 163*d310239dSOlivier Deprez entry.size, n, O_READ); 164*d310239dSOlivier Deprez } else { 165*d310239dSOlivier Deprez // TODO: set name depending on uuid node value 166*d310239dSOlivier Deprez make_dir_entry(c, dir, unk, entry.size, n, O_READ); 167*d310239dSOlivier Deprez } 168*d310239dSOlivier Deprez 169*d310239dSOlivier Deprez return 1; 170*d310239dSOlivier Deprez } 171*d310239dSOlivier Deprez 172*d310239dSOlivier Deprez static int fipwalk(chan_t *c, const char *name) 173*d310239dSOlivier Deprez { 174*d310239dSOlivier Deprez return devwalk(c, name, NULL, 0, fipgen); 175*d310239dSOlivier Deprez } 176*d310239dSOlivier Deprez 177*d310239dSOlivier Deprez static int fipstat(chan_t *c, const char *file, dir_t *dir) 178*d310239dSOlivier Deprez { 179*d310239dSOlivier Deprez return devstat(c, file, dir, NULL, 0, fipgen); 180*d310239dSOlivier Deprez } 181*d310239dSOlivier Deprez 182*d310239dSOlivier Deprez /******************************************************************************* 183*d310239dSOlivier Deprez * This function copies at most n bytes of the FIP image referred by c into 184*d310239dSOlivier Deprez * buf. 185*d310239dSOlivier Deprez ******************************************************************************/ 186*d310239dSOlivier Deprez static int fipread(chan_t *c, void *buf, int n) 187*d310239dSOlivier Deprez { 188*d310239dSOlivier Deprez long off; 189*d310239dSOlivier Deprez chan_t cs; 190*d310239dSOlivier Deprez struct fipfile *fip; 191*d310239dSOlivier Deprez long size; 192*d310239dSOlivier Deprez 193*d310239dSOlivier Deprez /* Only makes sense when using debug language */ 194*d310239dSOlivier Deprez assert(c->qid != CHDIR); 195*d310239dSOlivier Deprez 196*d310239dSOlivier Deprez if ((c->dev >= nfips) || ((c->qid & CHDIR) != 0)) { 197*d310239dSOlivier Deprez panic(); 198*d310239dSOlivier Deprez } 199*d310239dSOlivier Deprez 200*d310239dSOlivier Deprez fip = &archives[c->dev]; 201*d310239dSOlivier Deprez 202*d310239dSOlivier Deprez if ((c->qid >= NR_FILES) || (fip->offset[c->qid] < 0)) { 203*d310239dSOlivier Deprez panic(); 204*d310239dSOlivier Deprez } 205*d310239dSOlivier Deprez 206*d310239dSOlivier Deprez clone(fip->c, &cs); 207*d310239dSOlivier Deprez 208*d310239dSOlivier Deprez size = fip->size[c->qid]; 209*d310239dSOlivier Deprez if (c->offset >= size) { 210*d310239dSOlivier Deprez return 0; 211*d310239dSOlivier Deprez } 212*d310239dSOlivier Deprez 213*d310239dSOlivier Deprez if (n < 0) { 214*d310239dSOlivier Deprez return -1; 215*d310239dSOlivier Deprez } 216*d310239dSOlivier Deprez 217*d310239dSOlivier Deprez if (n > (size - c->offset)) { 218*d310239dSOlivier Deprez n = size - c->offset; 219*d310239dSOlivier Deprez } 220*d310239dSOlivier Deprez 221*d310239dSOlivier Deprez off = fip->offset[c->qid] + c->offset; 222*d310239dSOlivier Deprez if (devtab[cs.index]->seek(&cs, off, KSEEK_SET) < 0) { 223*d310239dSOlivier Deprez return -1; 224*d310239dSOlivier Deprez } 225*d310239dSOlivier Deprez 226*d310239dSOlivier Deprez n = devtab[cs.index]->read(&cs, buf, n); 227*d310239dSOlivier Deprez if (n > 0) { 228*d310239dSOlivier Deprez c->offset += n; 229*d310239dSOlivier Deprez } 230*d310239dSOlivier Deprez 231*d310239dSOlivier Deprez return n; 232*d310239dSOlivier Deprez } 233*d310239dSOlivier Deprez 234*d310239dSOlivier Deprez /******************************************************************************* 235*d310239dSOlivier Deprez * This function parses the FIP spec and registers its images in order to 236*d310239dSOlivier Deprez * expose them as files in the driver namespace. 237*d310239dSOlivier Deprez * It acts as an initialization function for the FIP driver. 238*d310239dSOlivier Deprez * It returns a pointer to the newly created channel. 239*d310239dSOlivier Deprez ******************************************************************************/ 240*d310239dSOlivier Deprez static chan_t *fipmount(chan_t *c, const char *spec) 241*d310239dSOlivier Deprez { 242*d310239dSOlivier Deprez int r, n, t; 243*d310239dSOlivier Deprez chan_t *cspec; 244*d310239dSOlivier Deprez uint32_t hname; 245*d310239dSOlivier Deprez struct fip_entry entry; 246*d310239dSOlivier Deprez struct fipfile *fip; 247*d310239dSOlivier Deprez dir_t dir; 248*d310239dSOlivier Deprez 249*d310239dSOlivier Deprez if (nfips == NR_FIPS) { 250*d310239dSOlivier Deprez return NULL; 251*d310239dSOlivier Deprez } 252*d310239dSOlivier Deprez 253*d310239dSOlivier Deprez fip = &archives[nfips]; 254*d310239dSOlivier Deprez 255*d310239dSOlivier Deprez for (n = 0; n < NR_FILES; n++) { 256*d310239dSOlivier Deprez fip->offset[n] = -1; 257*d310239dSOlivier Deprez } 258*d310239dSOlivier Deprez 259*d310239dSOlivier Deprez cspec = path_to_channel(spec, O_READ); 260*d310239dSOlivier Deprez if (cspec == NULL) { 261*d310239dSOlivier Deprez return NULL; 262*d310239dSOlivier Deprez } 263*d310239dSOlivier Deprez 264*d310239dSOlivier Deprez fip->c = cspec; 265*d310239dSOlivier Deprez 266*d310239dSOlivier Deprez r = devtab[cspec->index]->read(cspec, &hname, sizeof(hname)); 267*d310239dSOlivier Deprez if (r < 0) { 268*d310239dSOlivier Deprez goto err; 269*d310239dSOlivier Deprez } 270*d310239dSOlivier Deprez 271*d310239dSOlivier Deprez if ((r != sizeof(hname)) || (hname != TOC_HEADER_NAME)) { 272*d310239dSOlivier Deprez goto err; 273*d310239dSOlivier Deprez } 274*d310239dSOlivier Deprez 275*d310239dSOlivier Deprez if (stat(spec, &dir) < 0) { 276*d310239dSOlivier Deprez goto err; 277*d310239dSOlivier Deprez } 278*d310239dSOlivier Deprez 279*d310239dSOlivier Deprez t = cspec->index; 280*d310239dSOlivier Deprez if (devtab[t]->seek(cspec, STOC_HEADER, KSEEK_SET) < 0) { 281*d310239dSOlivier Deprez goto err; 282*d310239dSOlivier Deprez } 283*d310239dSOlivier Deprez 284*d310239dSOlivier Deprez for (n = 0; n < NR_FILES; n++) { 285*d310239dSOlivier Deprez switch (get_entry(cspec, &entry)) { 286*d310239dSOlivier Deprez case 0: 287*d310239dSOlivier Deprez return attach('F', nfips++); 288*d310239dSOlivier Deprez case -1: 289*d310239dSOlivier Deprez goto err; 290*d310239dSOlivier Deprez default: 291*d310239dSOlivier Deprez if ((entry.offset_address + entry.size) > dir.length) { 292*d310239dSOlivier Deprez goto err; 293*d310239dSOlivier Deprez } 294*d310239dSOlivier Deprez 295*d310239dSOlivier Deprez fip->offset[n] = entry.offset_address; 296*d310239dSOlivier Deprez fip->size[n] = entry.size; 297*d310239dSOlivier Deprez break; 298*d310239dSOlivier Deprez } 299*d310239dSOlivier Deprez } 300*d310239dSOlivier Deprez 301*d310239dSOlivier Deprez err: 302*d310239dSOlivier Deprez channel_close(cspec); 303*d310239dSOlivier Deprez return NULL; 304*d310239dSOlivier Deprez } 305*d310239dSOlivier Deprez 306*d310239dSOlivier Deprez const dev_t fipdevtab = { 307*d310239dSOlivier Deprez .id = 'F', 308*d310239dSOlivier Deprez .stat = fipstat, 309*d310239dSOlivier Deprez .clone = devclone, 310*d310239dSOlivier Deprez .attach = devattach, 311*d310239dSOlivier Deprez .walk = fipwalk, 312*d310239dSOlivier Deprez .read = fipread, 313*d310239dSOlivier Deprez .write = deverrwrite, 314*d310239dSOlivier Deprez .mount = fipmount, 315*d310239dSOlivier Deprez .seek = devseek 316*d310239dSOlivier Deprez }; 317*d310239dSOlivier Deprez 318