xref: /openbmc/u-boot/common/bloblist.c (revision 9450ab2b)
1*9f407d4eSSimon Glass // SPDX-License-Identifier: GPL-2.0+
2*9f407d4eSSimon Glass /*
3*9f407d4eSSimon Glass  * Copyright 2018 Google, Inc
4*9f407d4eSSimon Glass  * Written by Simon Glass <sjg@chromium.org>
5*9f407d4eSSimon Glass  */
6*9f407d4eSSimon Glass 
7*9f407d4eSSimon Glass #include <common.h>
8*9f407d4eSSimon Glass #include <bloblist.h>
9*9f407d4eSSimon Glass #include <log.h>
10*9f407d4eSSimon Glass #include <mapmem.h>
11*9f407d4eSSimon Glass #include <spl.h>
12*9f407d4eSSimon Glass 
13*9f407d4eSSimon Glass DECLARE_GLOBAL_DATA_PTR;
14*9f407d4eSSimon Glass 
bloblist_first_blob(struct bloblist_hdr * hdr)15*9f407d4eSSimon Glass struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
16*9f407d4eSSimon Glass {
17*9f407d4eSSimon Glass 	if (hdr->alloced <= hdr->hdr_size)
18*9f407d4eSSimon Glass 		return NULL;
19*9f407d4eSSimon Glass 	return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
20*9f407d4eSSimon Glass }
21*9f407d4eSSimon Glass 
bloblist_next_blob(struct bloblist_hdr * hdr,struct bloblist_rec * rec)22*9f407d4eSSimon Glass struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
23*9f407d4eSSimon Glass 					struct bloblist_rec *rec)
24*9f407d4eSSimon Glass {
25*9f407d4eSSimon Glass 	ulong offset;
26*9f407d4eSSimon Glass 
27*9f407d4eSSimon Glass 	offset = (void *)rec - (void *)hdr;
28*9f407d4eSSimon Glass 	offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN);
29*9f407d4eSSimon Glass 	if (offset >= hdr->alloced)
30*9f407d4eSSimon Glass 		return NULL;
31*9f407d4eSSimon Glass 	return (struct bloblist_rec *)((void *)hdr + offset);
32*9f407d4eSSimon Glass }
33*9f407d4eSSimon Glass 
34*9f407d4eSSimon Glass #define foreach_rec(_rec, _hdr) \
35*9f407d4eSSimon Glass 	for (_rec = bloblist_first_blob(_hdr); \
36*9f407d4eSSimon Glass 	     _rec; \
37*9f407d4eSSimon Glass 	     _rec = bloblist_next_blob(_hdr, _rec))
38*9f407d4eSSimon Glass 
bloblist_findrec(uint tag)39*9f407d4eSSimon Glass static struct bloblist_rec *bloblist_findrec(uint tag)
40*9f407d4eSSimon Glass {
41*9f407d4eSSimon Glass 	struct bloblist_hdr *hdr = gd->bloblist;
42*9f407d4eSSimon Glass 	struct bloblist_rec *rec;
43*9f407d4eSSimon Glass 
44*9f407d4eSSimon Glass 	if (!hdr)
45*9f407d4eSSimon Glass 		return NULL;
46*9f407d4eSSimon Glass 
47*9f407d4eSSimon Glass 	foreach_rec(rec, hdr) {
48*9f407d4eSSimon Glass 		if (rec->tag == tag)
49*9f407d4eSSimon Glass 			return rec;
50*9f407d4eSSimon Glass 	}
51*9f407d4eSSimon Glass 
52*9f407d4eSSimon Glass 	return NULL;
53*9f407d4eSSimon Glass }
54*9f407d4eSSimon Glass 
bloblist_addrec(uint tag,int size,struct bloblist_rec ** recp)55*9f407d4eSSimon Glass static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp)
56*9f407d4eSSimon Glass {
57*9f407d4eSSimon Glass 	struct bloblist_hdr *hdr = gd->bloblist;
58*9f407d4eSSimon Glass 	struct bloblist_rec *rec;
59*9f407d4eSSimon Glass 	int new_alloced;
60*9f407d4eSSimon Glass 
61*9f407d4eSSimon Glass 	new_alloced = hdr->alloced + sizeof(*rec) +
62*9f407d4eSSimon Glass 			ALIGN(size, BLOBLIST_ALIGN);
63*9f407d4eSSimon Glass 	if (new_alloced >= hdr->size) {
64*9f407d4eSSimon Glass 		log(LOGC_BLOBLIST, LOGL_ERR,
65*9f407d4eSSimon Glass 		    "Failed to allocate %x bytes size=%x, need size>=%x\n",
66*9f407d4eSSimon Glass 		    size, hdr->size, new_alloced);
67*9f407d4eSSimon Glass 		return log_msg_ret("bloblist add", -ENOSPC);
68*9f407d4eSSimon Glass 	}
69*9f407d4eSSimon Glass 	rec = (void *)hdr + hdr->alloced;
70*9f407d4eSSimon Glass 	hdr->alloced = new_alloced;
71*9f407d4eSSimon Glass 
72*9f407d4eSSimon Glass 	rec->tag = tag;
73*9f407d4eSSimon Glass 	rec->hdr_size = sizeof(*rec);
74*9f407d4eSSimon Glass 	rec->size = size;
75*9f407d4eSSimon Glass 	rec->spare = 0;
76*9f407d4eSSimon Glass 	*recp = rec;
77*9f407d4eSSimon Glass 
78*9f407d4eSSimon Glass 	return 0;
79*9f407d4eSSimon Glass }
80*9f407d4eSSimon Glass 
bloblist_ensurerec(uint tag,struct bloblist_rec ** recp,int size)81*9f407d4eSSimon Glass static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size)
82*9f407d4eSSimon Glass {
83*9f407d4eSSimon Glass 	struct bloblist_rec *rec;
84*9f407d4eSSimon Glass 
85*9f407d4eSSimon Glass 	rec = bloblist_findrec(tag);
86*9f407d4eSSimon Glass 	if (rec) {
87*9f407d4eSSimon Glass 		if (size && size != rec->size)
88*9f407d4eSSimon Glass 			return -ESPIPE;
89*9f407d4eSSimon Glass 	} else {
90*9f407d4eSSimon Glass 		int ret;
91*9f407d4eSSimon Glass 
92*9f407d4eSSimon Glass 		ret = bloblist_addrec(tag, size, &rec);
93*9f407d4eSSimon Glass 		if (ret)
94*9f407d4eSSimon Glass 			return ret;
95*9f407d4eSSimon Glass 	}
96*9f407d4eSSimon Glass 	*recp = rec;
97*9f407d4eSSimon Glass 
98*9f407d4eSSimon Glass 	return 0;
99*9f407d4eSSimon Glass }
100*9f407d4eSSimon Glass 
bloblist_find(uint tag,int size)101*9f407d4eSSimon Glass void *bloblist_find(uint tag, int size)
102*9f407d4eSSimon Glass {
103*9f407d4eSSimon Glass 	struct bloblist_rec *rec;
104*9f407d4eSSimon Glass 
105*9f407d4eSSimon Glass 	rec = bloblist_findrec(tag);
106*9f407d4eSSimon Glass 	if (!rec)
107*9f407d4eSSimon Glass 		return NULL;
108*9f407d4eSSimon Glass 	if (size && size != rec->size)
109*9f407d4eSSimon Glass 		return NULL;
110*9f407d4eSSimon Glass 
111*9f407d4eSSimon Glass 	return (void *)rec + rec->hdr_size;
112*9f407d4eSSimon Glass }
113*9f407d4eSSimon Glass 
bloblist_add(uint tag,int size)114*9f407d4eSSimon Glass void *bloblist_add(uint tag, int size)
115*9f407d4eSSimon Glass {
116*9f407d4eSSimon Glass 	struct bloblist_rec *rec;
117*9f407d4eSSimon Glass 
118*9f407d4eSSimon Glass 	if (bloblist_addrec(tag, size, &rec))
119*9f407d4eSSimon Glass 		return NULL;
120*9f407d4eSSimon Glass 
121*9f407d4eSSimon Glass 	return rec + 1;
122*9f407d4eSSimon Glass }
123*9f407d4eSSimon Glass 
bloblist_ensure_size(uint tag,int size,void ** blobp)124*9f407d4eSSimon Glass int bloblist_ensure_size(uint tag, int size, void **blobp)
125*9f407d4eSSimon Glass {
126*9f407d4eSSimon Glass 	struct bloblist_rec *rec;
127*9f407d4eSSimon Glass 	int ret;
128*9f407d4eSSimon Glass 
129*9f407d4eSSimon Glass 	ret = bloblist_ensurerec(tag, &rec, size);
130*9f407d4eSSimon Glass 	if (ret)
131*9f407d4eSSimon Glass 		return ret;
132*9f407d4eSSimon Glass 	*blobp = (void *)rec + rec->hdr_size;
133*9f407d4eSSimon Glass 
134*9f407d4eSSimon Glass 	return 0;
135*9f407d4eSSimon Glass }
136*9f407d4eSSimon Glass 
bloblist_ensure(uint tag,int size)137*9f407d4eSSimon Glass void *bloblist_ensure(uint tag, int size)
138*9f407d4eSSimon Glass {
139*9f407d4eSSimon Glass 	struct bloblist_rec *rec;
140*9f407d4eSSimon Glass 
141*9f407d4eSSimon Glass 	if (bloblist_ensurerec(tag, &rec, size))
142*9f407d4eSSimon Glass 		return NULL;
143*9f407d4eSSimon Glass 
144*9f407d4eSSimon Glass 	return (void *)rec + rec->hdr_size;
145*9f407d4eSSimon Glass }
146*9f407d4eSSimon Glass 
bloblist_calc_chksum(struct bloblist_hdr * hdr)147*9f407d4eSSimon Glass static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr)
148*9f407d4eSSimon Glass {
149*9f407d4eSSimon Glass 	struct bloblist_rec *rec;
150*9f407d4eSSimon Glass 	u32 chksum;
151*9f407d4eSSimon Glass 
152*9f407d4eSSimon Glass 	chksum = crc32(0, (unsigned char *)hdr,
153*9f407d4eSSimon Glass 		       offsetof(struct bloblist_hdr, chksum));
154*9f407d4eSSimon Glass 	foreach_rec(rec, hdr) {
155*9f407d4eSSimon Glass 		chksum = crc32(chksum, (void *)rec, rec->hdr_size);
156*9f407d4eSSimon Glass 		chksum = crc32(chksum, (void *)rec + rec->hdr_size, rec->size);
157*9f407d4eSSimon Glass 	}
158*9f407d4eSSimon Glass 
159*9f407d4eSSimon Glass 	return chksum;
160*9f407d4eSSimon Glass }
161*9f407d4eSSimon Glass 
bloblist_new(ulong addr,uint size,uint flags)162*9f407d4eSSimon Glass int bloblist_new(ulong addr, uint size, uint flags)
163*9f407d4eSSimon Glass {
164*9f407d4eSSimon Glass 	struct bloblist_hdr *hdr;
165*9f407d4eSSimon Glass 
166*9f407d4eSSimon Glass 	if (size < sizeof(*hdr))
167*9f407d4eSSimon Glass 		return log_ret(-ENOSPC);
168*9f407d4eSSimon Glass 	if (addr & (BLOBLIST_ALIGN - 1))
169*9f407d4eSSimon Glass 		return log_ret(-EFAULT);
170*9f407d4eSSimon Glass 	hdr = map_sysmem(addr, size);
171*9f407d4eSSimon Glass 	memset(hdr, '\0', sizeof(*hdr));
172*9f407d4eSSimon Glass 	hdr->version = BLOBLIST_VERSION;
173*9f407d4eSSimon Glass 	hdr->hdr_size = sizeof(*hdr);
174*9f407d4eSSimon Glass 	hdr->flags = flags;
175*9f407d4eSSimon Glass 	hdr->magic = BLOBLIST_MAGIC;
176*9f407d4eSSimon Glass 	hdr->size = size;
177*9f407d4eSSimon Glass 	hdr->alloced = hdr->hdr_size;
178*9f407d4eSSimon Glass 	hdr->chksum = 0;
179*9f407d4eSSimon Glass 	gd->bloblist = hdr;
180*9f407d4eSSimon Glass 
181*9f407d4eSSimon Glass 	return 0;
182*9f407d4eSSimon Glass }
183*9f407d4eSSimon Glass 
bloblist_check(ulong addr,uint size)184*9f407d4eSSimon Glass int bloblist_check(ulong addr, uint size)
185*9f407d4eSSimon Glass {
186*9f407d4eSSimon Glass 	struct bloblist_hdr *hdr;
187*9f407d4eSSimon Glass 	u32 chksum;
188*9f407d4eSSimon Glass 
189*9f407d4eSSimon Glass 	hdr = map_sysmem(addr, sizeof(*hdr));
190*9f407d4eSSimon Glass 	if (hdr->magic != BLOBLIST_MAGIC)
191*9f407d4eSSimon Glass 		return log_msg_ret("Bad magic", -ENOENT);
192*9f407d4eSSimon Glass 	if (hdr->version != BLOBLIST_VERSION)
193*9f407d4eSSimon Glass 		return log_msg_ret("Bad version", -EPROTONOSUPPORT);
194*9f407d4eSSimon Glass 	if (size && hdr->size != size)
195*9f407d4eSSimon Glass 		return log_msg_ret("Bad size", -EFBIG);
196*9f407d4eSSimon Glass 	chksum = bloblist_calc_chksum(hdr);
197*9f407d4eSSimon Glass 	if (hdr->chksum != chksum) {
198*9f407d4eSSimon Glass 		log(LOGC_BLOBLIST, LOGL_ERR, "Checksum %x != %x\n", hdr->chksum,
199*9f407d4eSSimon Glass 		    chksum);
200*9f407d4eSSimon Glass 		return log_msg_ret("Bad checksum", -EIO);
201*9f407d4eSSimon Glass 	}
202*9f407d4eSSimon Glass 	gd->bloblist = hdr;
203*9f407d4eSSimon Glass 
204*9f407d4eSSimon Glass 	return 0;
205*9f407d4eSSimon Glass }
206*9f407d4eSSimon Glass 
bloblist_finish(void)207*9f407d4eSSimon Glass int bloblist_finish(void)
208*9f407d4eSSimon Glass {
209*9f407d4eSSimon Glass 	struct bloblist_hdr *hdr = gd->bloblist;
210*9f407d4eSSimon Glass 
211*9f407d4eSSimon Glass 	hdr->chksum = bloblist_calc_chksum(hdr);
212*9f407d4eSSimon Glass 
213*9f407d4eSSimon Glass 	return 0;
214*9f407d4eSSimon Glass }
215*9f407d4eSSimon Glass 
bloblist_init(void)216*9f407d4eSSimon Glass int bloblist_init(void)
217*9f407d4eSSimon Glass {
218*9f407d4eSSimon Glass 	bool expected;
219*9f407d4eSSimon Glass 	int ret = -ENOENT;
220*9f407d4eSSimon Glass 
221*9f407d4eSSimon Glass 	/**
222*9f407d4eSSimon Glass 	 * Wed expect to find an existing bloblist in the first phase of U-Boot
223*9f407d4eSSimon Glass 	 * that runs
224*9f407d4eSSimon Glass 	 */
225*9f407d4eSSimon Glass 	expected = !u_boot_first_phase();
226*9f407d4eSSimon Glass 	if (expected)
227*9f407d4eSSimon Glass 		ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
228*9f407d4eSSimon Glass 				     CONFIG_BLOBLIST_SIZE);
229*9f407d4eSSimon Glass 	if (ret) {
230*9f407d4eSSimon Glass 		log(LOGC_BLOBLIST, expected ? LOGL_WARNING : LOGL_DEBUG,
231*9f407d4eSSimon Glass 		    "Existing bloblist not found: creating new bloblist\n");
232*9f407d4eSSimon Glass 		ret = bloblist_new(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE,
233*9f407d4eSSimon Glass 				   0);
234*9f407d4eSSimon Glass 	} else {
235*9f407d4eSSimon Glass 		log(LOGC_BLOBLIST, LOGL_DEBUG, "Found existing bloblist\n");
236*9f407d4eSSimon Glass 	}
237*9f407d4eSSimon Glass 
238*9f407d4eSSimon Glass 	return ret;
239*9f407d4eSSimon Glass }
240