9os

Experimental kernel using plan9 ideas for embedded device
git clone git://git.simple-cc.org/9os
Log | Files | Refs | README | LICENSE

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 };