devfip.c (6855B)
1 #include <os9/os9.h> 2 3 #include <errno.h> 4 #include <limits.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 #include <deserialize.h> 9 10 #include "dev.h" 11 #include "fip.h" 12 13 #define NR_FIPS 2 14 15 #define STOC_HEADER_NAME 4 /* strlen(TOC_HEADER_NAME); */ 16 #define STOC_HEADER 16 /* sizeof(fip_toc_header_t); */ 17 #define STOC_ENTRY 40 /* sizeof(fip_toc_entry_t); */ 18 19 struct fipfile { 20 Chan *c; 21 long offset[NR_FILES]; 22 long size[NR_FILES]; 23 }; 24 25 struct fipuuid { 26 char time_low[4]; 27 char time_mid[2]; 28 char time_hi_and_version[2]; 29 char clock_seq_hi_and_reserved; 30 char clock_seq_low; 31 char node[_UUID_NODE_LEN]; 32 }; 33 34 struct fipntry { 35 struct fipuuid uuid; 36 long long offset_address; 37 long long size; 38 long long flags; 39 }; 40 41 static struct fipfile archives[NR_FIPS]; 42 static int nfips; 43 44 45 static int 46 getntry(Chan *c, struct fipntry *ntry) 47 { 48 int i, n; 49 static unsigned char buf[STOC_ENTRY]; 50 51 n = devtab[c->type]->read(c, buf, sizeof(buf)); 52 if (n <= 0) 53 return n; 54 55 if (n != sizeof(buf)) { 56 seterror(EINVAL); 57 return -1; 58 } 59 60 n = 0; 61 for (i = 0; i < 4; i++) 62 CHAR(ntry->uuid.time_low[i], buf, n, sizeof(buf)); 63 for (i = 0; i < 2; i++) 64 CHAR(ntry->uuid.time_mid[i], buf, n, sizeof(buf)); 65 for (i = 0; i < 2; i++) 66 CHAR(ntry->uuid.time_hi_and_version[i], buf, n, sizeof(buf)); 67 CHAR(ntry->uuid.clock_seq_hi_and_reserved, buf, n, sizeof(buf)); 68 CHAR(ntry->uuid.clock_seq_low, buf, n, sizeof(buf)); 69 for (i = 0; i < _UUID_NODE_LEN; i++) 70 CHAR(ntry->uuid.node[i], buf, n, sizeof(buf)); 71 LLONG(ntry->offset_address, buf, n, sizeof(buf)); 72 LLONG(ntry->size, buf, n, sizeof(buf)); 73 LLONG(ntry->flags, buf, n, sizeof(buf)); 74 75 if (ntry->size > LONG_MAX || ntry->offset_address > LONG_MAX) { 76 seterror(EINVAL); 77 return -1; 78 } 79 80 if (ntry->size == 0) 81 return 0; 82 83 return 1; 84 } 85 86 static int 87 uuideq(struct fipuuid *u1, struct fipuuid *u2) 88 { 89 if (u1->clock_seq_hi_and_reserved != u2->clock_seq_hi_and_reserved) 90 return 0; 91 if (u1->clock_seq_low != u2->clock_seq_low) 92 return 0; 93 if (memcmp(u1->node, u2->node, sizeof(u1->node))) 94 return 0; 95 if (memcmp(u1->time_hi_and_version, u2->time_hi_and_version, sizeof(u1->time_hi_and_version))) 96 return 0; 97 if (memcmp(u1->time_low, u2->time_low, sizeof(u1->time_low))) 98 return 0; 99 if (memcmp(u1->time_mid, u2->time_mid, sizeof(u1->time_mid))) 100 return 0; 101 return 1; 102 } 103 104 static int 105 fipgen(Chan *c, Dirtab *tab, int ntab, int n, Dir *dir) 106 { 107 int i, r; 108 long off; 109 Chan nc; 110 struct fipntry ntry; 111 struct fipfile *fip; 112 static char unk[NAMELEN]; 113 114 struct uuidnames { 115 char name[NAMELEN]; 116 struct fipuuid uuid; 117 }; 118 119 // TODO: generate this array from a text file 120 static struct uuidnames uuidnames[] = { 121 {"scp-bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U}, 122 {"bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U}, 123 {"ns-bl2u.bin", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U}, 124 {"fwu.crt", UUID_TRUSTED_FWU_CERT}, 125 {"bl2.bin", UUID_TRUSTED_BOOT_FIRMWARE_BL2}, 126 {"scp-bl2.bin", UUID_SCP_FIRMWARE_SCP_BL2}, 127 {"bl31.bin", UUID_EL3_RUNTIME_FIRMWARE_BL31}, 128 {"bl32.bin", UUID_SECURE_PAYLOAD_BL32}, 129 {"bl32-xtr1.bin", UUID_SECURE_PAYLOAD_BL32_EXTRA1}, 130 {"bl32-xtr2.bin", UUID_SECURE_PAYLOAD_BL32_EXTRA2}, 131 {"bl33.bin", UUID_NON_TRUSTED_FIRMWARE_BL33}, 132 {"rot-k.crt", UUID_ROT_KEY_CERT}, 133 {"trstd-k.crt", UUID_TRUSTED_KEY_CERT}, 134 {"nt-k.crt", UUID_NON_TRUSTED_WORLD_KEY_CERT}, 135 {"scp-fw-k.crt", UUID_SCP_FW_KEY_CERT}, 136 {"soc-fw-k.crt", UUID_SOC_FW_KEY_CERT}, 137 {"tos-fw-k.crt", UUID_TRUSTED_OS_FW_KEY_CERT}, 138 {"nt-fw-k.crt", UUID_NON_TRUSTED_FW_KEY_CERT}, 139 {"tb-fw.crt", UUID_TRUSTED_BOOT_FW_CERT}, 140 {"scp-fw-c.crt", UUID_SCP_FW_CONTENT_CERT}, 141 {"soc-fw-c.crt", UUID_SOC_FW_CONTENT_CERT}, 142 {"tos-fw-c.crt", UUID_TRUSTED_OS_FW_CONTENT_CERT}, 143 {"nt-fw-c.crt", UUID_NON_TRUSTED_FW_CONTENT_CERT}, 144 {"hw.cfg", UUID_HW_CONFIG}, 145 {"tb-fw.cfg", UUID_TB_FW_CONFIG}, 146 {"soc-fw.cfg", UUID_SOC_FW_CONFIG}, 147 {"tos-fw.cfg", UUID_TOS_FW_CONFIG}, 148 {"nt-fw.cfg", UUID_NT_FW_CONFIG} 149 }; 150 151 if (c->dev >= nfips) 152 panic("fipgen"); 153 clone(archives[c->dev].c, &nc); 154 fip = &archives[nc.dev]; 155 156 off = STOC_HEADER; 157 for (i = 0; i <= n; i++) { 158 if (fip->offset[i] == -1) 159 return 0; 160 if (devtab[nc.type]->seek(&nc, off, SEEK_SET) < 0) 161 return -1; 162 if ((r = getntry(&nc, &ntry)) <= 0) 163 return r; 164 off += sizeof(ntry); 165 } 166 167 for (i = 0; i < NELEM(uuidnames); i++) { 168 if (uuideq(&uuidnames[i].uuid, &ntry.uuid)) 169 break; 170 } 171 172 if (i < NELEM(uuidnames)) { 173 mkentry(c, dir, 174 uuidnames[i].name, ntry.size, 175 QID(CHFILE, 0, n), O_READ); 176 } else { 177 // TODO: set name depending on uuid node value 178 mkentry(c, dir, 179 unk, ntry.size, 180 QID(CHFILE, 0, n), O_READ); 181 } 182 183 return 1; 184 } 185 186 static int 187 fipwalk(Chan *c, char *name) 188 { 189 return devwalk(c, name, NULL, 0, fipgen); 190 } 191 192 static int 193 fipstat(Chan *c, char *file, unsigned char *buf, int n) 194 { 195 return devstat(c, file, buf, n, NULL, 0, fipgen); 196 } 197 198 static int 199 fipread(Chan *c, void *buf, int n) 200 { 201 long off; 202 Chan cs; 203 struct fipfile *fip; 204 long size; 205 long long path; 206 207 if (c->qid.type == CHDIR) 208 return dirread(c, buf, n, NULL, 0, fipgen); 209 210 if (c->dev >= nfips) 211 panic("fipread1"); 212 fip = &archives[c->dev]; 213 214 path = c->qid.path; 215 if (path >= NR_FILES || fip->offset[path] < 0) 216 panic("fipread2"); 217 clone(fip->c, &cs); 218 219 size = fip->size[path]; 220 if (c->offset >= size) 221 return 0; 222 223 if (n < 0) { 224 seterror(EINVAL); 225 return -1; 226 } 227 if (n > size - c->offset) 228 n = size - c->offset; 229 230 off = fip->offset[path] + c->offset; 231 if (devtab[cs.type]->seek(&cs, off, SEEK_SET) < 0) 232 return -1; 233 234 n = devtab[cs.type]->read(&cs, buf, n); 235 if (n > 0) 236 c->offset += n; 237 238 return n; 239 } 240 241 static Chan * 242 fipmount(Chan *c, char *spec) 243 { 244 int r, n, t; 245 long name; 246 Chan *cspec; 247 unsigned char buf[STOC_HEADER_NAME]; 248 struct fipntry ntry; 249 struct fipfile *fip; 250 251 if (nfips == NR_FIPS) { 252 seterror(ENOMEM); 253 return NULL; 254 } 255 fip = &archives[nfips]; 256 257 for (n = 0; n < NR_FILES; n++) 258 fip->offset[n] = -1; 259 260 if ((cspec = namec(spec, O_READ)) == NULL) 261 return NULL; 262 fip->c = cspec; 263 264 r = devtab[cspec->type]->read(cspec, buf, STOC_HEADER_NAME); 265 if (r < 0) 266 goto err; 267 n = 0; 268 LONG(name, buf, n, sizeof(buf)); 269 if (r != STOC_HEADER_NAME || name != TOC_HEADER_NAME) { 270 seterror(EINVAL); 271 goto err; 272 } 273 274 t = cspec->type; 275 if (devtab[t]->seek(cspec, STOC_HEADER, SEEK_SET) < 0) 276 goto err; 277 for (n = 0; n < NR_FILES; n++) { 278 switch (getntry(cspec, &ntry)) { 279 case 0: 280 return attach('F', nfips++); 281 case -1: 282 goto err; 283 default: 284 fip->offset[n] = ntry.offset_address; 285 fip->size[n] = ntry.size; 286 break; 287 } 288 } 289 seterror(ENOMEM); 290 291 err: 292 chanclose(cspec); 293 return NULL; 294 } 295 296 Dev fipdevtab = { 297 .id = 'F', 298 .stat = fipstat, 299 .clone = devclone, 300 .attach = devattach, 301 .walk = fipwalk, 302 .read = fipread, 303 .write = deverrwrite, 304 .mount = fipmount, 305 .seek = devseek, 306 .sync = devsync, 307 .close = devclose, 308 };