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