blob: 5a25719032fe2b200df6b6ff7d594102fd32de59 [file] [log] [blame]
Angel Pons118a9c72020-04-02 23:48:34 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Aaron Durbin20686d82015-03-05 14:11:27 -06003
4#include <assert.h>
5#include <cbmem.h>
6#include <console/console.h>
7#include <imd.h>
8#include <stdlib.h>
9#include <string.h>
Julius Wernera2148372019-11-13 19:50:33 -080010#include <types.h>
Aaron Durbin20686d82015-03-05 14:11:27 -060011
12/* For more details on implementation and usage please see the imd.h header. */
13
14static const uint32_t IMD_ROOT_PTR_MAGIC = 0xc0389481;
15static const uint32_t IMD_ENTRY_MAGIC = ~0xc0389481;
Aaron Durbincac50502015-03-24 23:14:46 -050016static const uint32_t SMALL_REGION_ID = CBMEM_ID_IMD_SMALL;
Aaron Durbin20686d82015-03-05 14:11:27 -060017static const size_t LIMIT_ALIGN = 4096;
18
19/* In-memory data structures. */
20struct imd_root_pointer {
21 uint32_t magic;
22 /* Relative to upper limit/offset. */
23 int32_t root_offset;
Stefan Reinauer6a001132017-07-13 02:20:27 +020024} __packed;
Aaron Durbin20686d82015-03-05 14:11:27 -060025
26struct imd_entry {
27 uint32_t magic;
28 /* start is located relative to imd_root */
29 int32_t start_offset;
30 uint32_t size;
31 uint32_t id;
Stefan Reinauer6a001132017-07-13 02:20:27 +020032} __packed;
Aaron Durbin20686d82015-03-05 14:11:27 -060033
34struct imd_root {
35 uint32_t max_entries;
36 uint32_t num_entries;
37 uint32_t flags;
38 uint32_t entry_align;
39 /* Used for fixing the size of an imd. Relative to the root. */
40 int32_t max_offset;
41 struct imd_entry entries[0];
Stefan Reinauer6a001132017-07-13 02:20:27 +020042} __packed;
Aaron Durbin20686d82015-03-05 14:11:27 -060043
44#define IMD_FLAG_LOCKED 1
45
46static void *relative_pointer(void *base, ssize_t offset)
47{
48 intptr_t b = (intptr_t)base;
49 b += offset;
50 return (void *)b;
51}
52
53static bool imd_root_pointer_valid(const struct imd_root_pointer *rp)
54{
55 return !!(rp->magic == IMD_ROOT_PTR_MAGIC);
56}
57
Aaron Durbincac50502015-03-24 23:14:46 -050058static struct imd_root *imdr_root(const struct imdr *imdr)
Aaron Durbin20686d82015-03-05 14:11:27 -060059{
Aaron Durbincac50502015-03-24 23:14:46 -050060 return imdr->r;
Aaron Durbin20686d82015-03-05 14:11:27 -060061}
62
63/*
64 * The root pointer is relative to the upper limit of the imd. i.e. It sits
65 * just below the upper limit.
66 */
Aaron Durbincac50502015-03-24 23:14:46 -050067static struct imd_root_pointer *imdr_get_root_pointer(const struct imdr *imdr)
Aaron Durbin20686d82015-03-05 14:11:27 -060068{
69 struct imd_root_pointer *rp;
70
Aaron Durbincac50502015-03-24 23:14:46 -050071 rp = relative_pointer((void *)imdr->limit, -sizeof(*rp));
Aaron Durbin20686d82015-03-05 14:11:27 -060072
73 return rp;
74}
75
76static void imd_link_root(struct imd_root_pointer *rp, struct imd_root *r)
77{
78 rp->magic = IMD_ROOT_PTR_MAGIC;
79 rp->root_offset = (int32_t)((intptr_t)r - (intptr_t)rp);
80}
81
Aaron Durbincac50502015-03-24 23:14:46 -050082static struct imd_entry *root_last_entry(struct imd_root *r)
83{
84 return &r->entries[r->num_entries - 1];
85}
86
87static size_t root_num_entries(size_t root_size)
88{
89 size_t entries_size;
90
91 entries_size = root_size;
92 entries_size -= sizeof(struct imd_root_pointer);
93 entries_size -= sizeof(struct imd_root);
94
95 return entries_size / sizeof(struct imd_entry);
96}
97
98static size_t imd_root_data_left(struct imd_root *r)
99{
100 struct imd_entry *last_entry;
101
102 last_entry = root_last_entry(r);
103
104 if (r->max_offset != 0)
105 return last_entry->start_offset - r->max_offset;
106
107 return ~(size_t)0;
108}
109
110static bool root_is_locked(const struct imd_root *r)
111{
112 return !!(r->flags & IMD_FLAG_LOCKED);
113}
114
Aaron Durbin20686d82015-03-05 14:11:27 -0600115static void imd_entry_assign(struct imd_entry *e, uint32_t id,
116 ssize_t offset, size_t size)
117{
118 e->magic = IMD_ENTRY_MAGIC;
119 e->start_offset = offset;
120 e->size = size;
121 e->id = id;
122}
123
Aaron Durbincac50502015-03-24 23:14:46 -0500124static void imdr_init(struct imdr *ir, void *upper_limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600125{
126 uintptr_t limit = (uintptr_t)upper_limit;
127 /* Upper limit is aligned down to 4KiB */
Aaron Durbincac50502015-03-24 23:14:46 -0500128 ir->limit = ALIGN_DOWN(limit, LIMIT_ALIGN);
129 ir->r = NULL;
Aaron Durbin20686d82015-03-05 14:11:27 -0600130}
131
Aaron Durbincac50502015-03-24 23:14:46 -0500132static int imdr_create_empty(struct imdr *imdr, size_t root_size,
133 size_t entry_align)
Aaron Durbin20686d82015-03-05 14:11:27 -0600134{
135 struct imd_root_pointer *rp;
136 struct imd_root *r;
137 struct imd_entry *e;
138 ssize_t root_offset;
Aaron Durbin20686d82015-03-05 14:11:27 -0600139
Aaron Durbincac50502015-03-24 23:14:46 -0500140 if (!imdr->limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600141 return -1;
142
143 /* root_size and entry_align should be a power of 2. */
144 assert(IS_POWER_OF_2(root_size));
145 assert(IS_POWER_OF_2(entry_align));
146
Aaron Durbincac50502015-03-24 23:14:46 -0500147 if (!imdr->limit)
148 return -1;
149
Aaron Durbin20686d82015-03-05 14:11:27 -0600150 /*
Martin Roth2ed0aa22016-01-05 20:58:58 -0700151 * root_size needs to be large enough to accommodate root pointer and
Aaron Durbin20686d82015-03-05 14:11:27 -0600152 * root book keeping structure. The caller needs to ensure there's
153 * enough room for tracking individual allocations.
154 */
155 if (root_size < (sizeof(*rp) + sizeof(*r)))
156 return -1;
157
Lee Leahy73402172017-03-10 15:23:24 -0800158 /* For simplicity don't allow sizes or alignments to exceed LIMIT_ALIGN.
159 */
Aaron Durbin20686d82015-03-05 14:11:27 -0600160 if (root_size > LIMIT_ALIGN || entry_align > LIMIT_ALIGN)
161 return -1;
162
163 /* Additionally, don't handle an entry alignment > root_size. */
164 if (entry_align > root_size)
165 return -1;
166
Aaron Durbincac50502015-03-24 23:14:46 -0500167 rp = imdr_get_root_pointer(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600168
169 root_offset = -(ssize_t)root_size;
170 /* Set root pointer. */
Aaron Durbincac50502015-03-24 23:14:46 -0500171 imdr->r = relative_pointer((void *)imdr->limit, root_offset);
172 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600173 imd_link_root(rp, r);
174
175 memset(r, 0, sizeof(*r));
176 r->entry_align = entry_align;
177
178 /* Calculate size left for entries. */
Aaron Durbincac50502015-03-24 23:14:46 -0500179 r->max_entries = root_num_entries(root_size);
Aaron Durbin20686d82015-03-05 14:11:27 -0600180
181 /* Fill in first entry covering the root region. */
182 r->num_entries = 1;
183 e = &r->entries[0];
184 imd_entry_assign(e, CBMEM_ID_IMD_ROOT, 0, root_size);
185
186 printk(BIOS_DEBUG, "IMD: root @ %p %u entries.\n", r, r->max_entries);
187
188 return 0;
189}
190
Aaron Durbincac50502015-03-24 23:14:46 -0500191static int imdr_recover(struct imdr *imdr)
Aaron Durbin20686d82015-03-05 14:11:27 -0600192{
193 struct imd_root_pointer *rp;
194 struct imd_root *r;
195 uintptr_t low_limit;
196 size_t i;
197
Aaron Durbincac50502015-03-24 23:14:46 -0500198 if (!imdr->limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600199 return -1;
200
Aaron Durbincac50502015-03-24 23:14:46 -0500201 rp = imdr_get_root_pointer(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600202
203 if (!imd_root_pointer_valid(rp))
204 return -1;
205
206 r = relative_pointer(rp, rp->root_offset);
207
208 /* Confirm the root and root pointer are just under the limit. */
209 if (ALIGN_UP((uintptr_t)&r->entries[r->max_entries], LIMIT_ALIGN) !=
Aaron Durbincac50502015-03-24 23:14:46 -0500210 imdr->limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600211 return -1;
212
213 if (r->num_entries > r->max_entries)
214 return -1;
215
216 /* Entry alignment should be power of 2. */
217 if (!IS_POWER_OF_2(r->entry_align))
218 return -1;
219
220 low_limit = (uintptr_t)relative_pointer(r, r->max_offset);
221
222 /* If no max_offset then lowest limit is 0. */
223 if (low_limit == (uintptr_t)r)
224 low_limit = 0;
225
226 for (i = 0; i < r->num_entries; i++) {
227 uintptr_t start_addr;
228 const struct imd_entry *e = &r->entries[i];
229
230 if (e->magic != IMD_ENTRY_MAGIC)
231 return -1;
232
233 start_addr = (uintptr_t)relative_pointer(r, e->start_offset);
234 if (start_addr < low_limit)
235 return -1;
Aaron Durbincac50502015-03-24 23:14:46 -0500236 if (start_addr >= imdr->limit ||
237 (start_addr + e->size) > imdr->limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600238 return -1;
239 }
240
241 /* Set root pointer. */
Aaron Durbincac50502015-03-24 23:14:46 -0500242 imdr->r = r;
Aaron Durbin20686d82015-03-05 14:11:27 -0600243
244 return 0;
245}
246
Aaron Durbincac50502015-03-24 23:14:46 -0500247static const struct imd_entry *imdr_entry_find(const struct imdr *imdr,
248 uint32_t id)
Aaron Durbin20686d82015-03-05 14:11:27 -0600249{
250 struct imd_root *r;
251 struct imd_entry *e;
Aaron Durbincac50502015-03-24 23:14:46 -0500252 size_t i;
Aaron Durbin20686d82015-03-05 14:11:27 -0600253
Aaron Durbincac50502015-03-24 23:14:46 -0500254 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600255
Aaron Durbincac50502015-03-24 23:14:46 -0500256 if (r == NULL)
257 return NULL;
Aaron Durbin20686d82015-03-05 14:11:27 -0600258
Aaron Durbincac50502015-03-24 23:14:46 -0500259 e = NULL;
260 /* Skip first entry covering the root. */
261 for (i = 1; i < r->num_entries; i++) {
262 if (id != r->entries[i].id)
263 continue;
264 e = &r->entries[i];
265 break;
266 }
267
268 return e;
269}
270
271static int imdr_limit_size(struct imdr *imdr, size_t max_size)
272{
273 struct imd_root *r;
274 ssize_t smax_size;
275 size_t root_size;
276
277 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600278 if (r == NULL)
279 return -1;
280
Aaron Durbincac50502015-03-24 23:14:46 -0500281 root_size = imdr->limit - (uintptr_t)r;
Aaron Durbin20686d82015-03-05 14:11:27 -0600282
Aaron Durbincac50502015-03-24 23:14:46 -0500283 if (max_size < root_size)
284 return -1;
Aaron Durbin20686d82015-03-05 14:11:27 -0600285
Aaron Durbincac50502015-03-24 23:14:46 -0500286 /* Take into account the root size. */
287 smax_size = max_size - root_size;
288 smax_size = -smax_size;
Aaron Durbin20686d82015-03-05 14:11:27 -0600289
Aaron Durbincac50502015-03-24 23:14:46 -0500290 r->max_offset = smax_size;
Aaron Durbin20686d82015-03-05 14:11:27 -0600291
292 return 0;
293}
294
Aaron Durbincac50502015-03-24 23:14:46 -0500295static size_t imdr_entry_size(const struct imdr *imdr,
296 const struct imd_entry *e)
297{
298 return e->size;
299}
300
301static void *imdr_entry_at(const struct imdr *imdr, const struct imd_entry *e)
302{
303 return relative_pointer(imdr_root(imdr), e->start_offset);
304}
305
Aaron Durbin20686d82015-03-05 14:11:27 -0600306static struct imd_entry *imd_entry_add_to_root(struct imd_root *r, uint32_t id,
307 size_t size)
308{
309 struct imd_entry *entry;
310 struct imd_entry *last_entry;
311 ssize_t e_offset;
312 size_t used_size;
313
314 if (r->num_entries == r->max_entries)
315 return NULL;
316
317 /* Determine total size taken up by entry. */
318 used_size = ALIGN_UP(size, r->entry_align);
319
Aaron Durbin20686d82015-03-05 14:11:27 -0600320 /* See if size overflows imd total size. */
Aaron Durbincac50502015-03-24 23:14:46 -0500321 if (used_size > imd_root_data_left(r))
322 return NULL;
Aaron Durbin20686d82015-03-05 14:11:27 -0600323
324 /*
325 * Determine if offset field overflows. All offsets should be lower
326 * than the previous one.
327 */
Aaron Durbincac50502015-03-24 23:14:46 -0500328 last_entry = root_last_entry(r);
Aaron Durbin20686d82015-03-05 14:11:27 -0600329 e_offset = last_entry->start_offset;
330 e_offset -= (ssize_t)used_size;
331 if (e_offset > last_entry->start_offset)
332 return NULL;
333
334 entry = root_last_entry(r) + 1;
335 r->num_entries++;
336
337 imd_entry_assign(entry, id, e_offset, size);
338
339 return entry;
340}
341
Aaron Durbincac50502015-03-24 23:14:46 -0500342static const struct imd_entry *imdr_entry_add(const struct imdr *imdr,
343 uint32_t id, size_t size)
Aaron Durbin20686d82015-03-05 14:11:27 -0600344{
345 struct imd_root *r;
346
Aaron Durbincac50502015-03-24 23:14:46 -0500347 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600348
349 if (r == NULL)
350 return NULL;
351
352 if (root_is_locked(r))
353 return NULL;
354
355 return imd_entry_add_to_root(r, id, size);
356}
357
Aaron Durbincac50502015-03-24 23:14:46 -0500358static bool imdr_has_entry(const struct imdr *imdr, const struct imd_entry *e)
359{
360 struct imd_root *r;
361 size_t idx;
362
363 r = imdr_root(imdr);
364 if (r == NULL)
365 return false;
366
367 /* Determine if the entry is within this root structure. */
368 idx = e - &r->entries[0];
369 if (idx >= r->num_entries)
370 return false;
371
372 return true;
373}
374
375static const struct imdr *imd_entry_to_imdr(const struct imd *imd,
376 const struct imd_entry *entry)
377{
378 if (imdr_has_entry(&imd->lg, entry))
379 return &imd->lg;
380
381 if (imdr_has_entry(&imd->sm, entry))
382 return &imd->sm;
383
384 return NULL;
385}
386
387/* Initialize imd handle. */
388void imd_handle_init(struct imd *imd, void *upper_limit)
389{
390 imdr_init(&imd->lg, upper_limit);
391 imdr_init(&imd->sm, NULL);
392}
393
394void imd_handle_init_partial_recovery(struct imd *imd)
395{
396 const struct imd_entry *e;
397 struct imd_root_pointer *rp;
398 struct imdr *imdr;
399
Aaron Durbin01562b62015-05-11 14:19:37 -0500400 if (imd->lg.limit == 0)
401 return;
402
Aaron Durbincac50502015-03-24 23:14:46 -0500403 imd_handle_init(imd, (void *)imd->lg.limit);
404
405 /* Initialize root pointer for the large regions. */
406 imdr = &imd->lg;
407 rp = imdr_get_root_pointer(imdr);
408 imdr->r = relative_pointer(rp, rp->root_offset);
409
410 e = imdr_entry_find(imdr, SMALL_REGION_ID);
411
412 if (e == NULL)
413 return;
414
415 imd->sm.limit = (uintptr_t)imdr_entry_at(imdr, e);
416 imd->sm.limit += imdr_entry_size(imdr, e);
417 imdr = &imd->sm;
418 rp = imdr_get_root_pointer(imdr);
419 imdr->r = relative_pointer(rp, rp->root_offset);
420}
421
422int imd_create_empty(struct imd *imd, size_t root_size, size_t entry_align)
423{
424 return imdr_create_empty(&imd->lg, root_size, entry_align);
425}
426
427int imd_create_tiered_empty(struct imd *imd,
428 size_t lg_root_size, size_t lg_entry_align,
429 size_t sm_root_size, size_t sm_entry_align)
430{
Lee Leahy3e1cab42017-03-10 17:48:31 -0800431 size_t sm_region_size;
Aaron Durbincac50502015-03-24 23:14:46 -0500432 const struct imd_entry *e;
433 struct imdr *imdr;
434
435 imdr = &imd->lg;
436
437 if (imdr_create_empty(imdr, lg_root_size, lg_entry_align) != 0)
438 return -1;
439
440 /* Calculate the size of the small region to request. */
441 sm_region_size = root_num_entries(sm_root_size) * sm_entry_align;
442 sm_region_size += sm_root_size;
443 sm_region_size = ALIGN_UP(sm_region_size, lg_entry_align);
444
445 /* Add a new entry to the large region to cover the root and entries. */
446 e = imdr_entry_add(imdr, SMALL_REGION_ID, sm_region_size);
447
448 if (e == NULL)
449 goto fail;
450
451 imd->sm.limit = (uintptr_t)imdr_entry_at(imdr, e);
452 imd->sm.limit += sm_region_size;
453
454 if (imdr_create_empty(&imd->sm, sm_root_size, sm_entry_align) != 0 ||
455 imdr_limit_size(&imd->sm, sm_region_size))
456 goto fail;
457
458 return 0;
459fail:
460 imd_handle_init(imd, (void *)imdr->limit);
461 return -1;
462}
463
464int imd_recover(struct imd *imd)
465{
466 const struct imd_entry *e;
467 uintptr_t small_upper_limit;
468 struct imdr *imdr;
469
470 imdr = &imd->lg;
471 if (imdr_recover(imdr) != 0)
472 return -1;
473
474 /* Determine if small region is region is present. */
475 e = imdr_entry_find(imdr, SMALL_REGION_ID);
476
477 if (e == NULL)
478 return 0;
479
480 small_upper_limit = (uintptr_t)imdr_entry_at(imdr, e);
481 small_upper_limit += imdr_entry_size(imdr, e);
482
483 imd->sm.limit = small_upper_limit;
484
485 /* Tear down any changes on failure. */
486 if (imdr_recover(&imd->sm) != 0) {
487 imd_handle_init(imd, (void *)imd->lg.limit);
488 return -1;
489 }
490
491 return 0;
492}
493
494int imd_limit_size(struct imd *imd, size_t max_size)
495{
496 return imdr_limit_size(&imd->lg, max_size);
497}
498
499int imd_lockdown(struct imd *imd)
500{
501 struct imd_root *r;
502
503 r = imdr_root(&imd->lg);
504 if (r == NULL)
505 return -1;
506
507 r->flags |= IMD_FLAG_LOCKED;
508
509 r = imdr_root(&imd->sm);
510 if (r != NULL)
511 r->flags |= IMD_FLAG_LOCKED;
512
513 return 0;
514}
515
516int imd_region_used(struct imd *imd, void **base, size_t *size)
Aaron Durbin20686d82015-03-05 14:11:27 -0600517{
518 struct imd_root *r;
519 struct imd_entry *e;
Aaron Durbincac50502015-03-24 23:14:46 -0500520 void *low_addr;
521 size_t sz_used;
Aaron Durbin20686d82015-03-05 14:11:27 -0600522
Aaron Durbincac50502015-03-24 23:14:46 -0500523 if (!imd->lg.limit)
524 return -1;
525
526 r = imdr_root(&imd->lg);
Aaron Durbin20686d82015-03-05 14:11:27 -0600527
528 if (r == NULL)
Aaron Durbincac50502015-03-24 23:14:46 -0500529 return -1;
Aaron Durbin20686d82015-03-05 14:11:27 -0600530
Aaron Durbincac50502015-03-24 23:14:46 -0500531 /* Use last entry to obtain lowest address. */
532 e = root_last_entry(r);
533
534 low_addr = relative_pointer(r, e->start_offset);
535
536 /* Total size used is the last entry's base up to the limit. */
537 sz_used = imd->lg.limit - (uintptr_t)low_addr;
538
539 *base = low_addr;
540 *size = sz_used;
541
542 return 0;
543}
544
545const struct imd_entry *imd_entry_add(const struct imd *imd, uint32_t id,
546 size_t size)
547{
548 struct imd_root *r;
549 const struct imdr *imdr;
550 const struct imd_entry *e = NULL;
551
552 /*
553 * Determine if requested size is less than 1/4 of small data
554 * region is left.
555 */
556 imdr = &imd->sm;
557 r = imdr_root(imdr);
558
559 /* No small region. Use the large region. */
560 if (r == NULL)
561 return imdr_entry_add(&imd->lg, id, size);
562 else if (size <= r->entry_align || size <= imd_root_data_left(r) / 4)
563 e = imdr_entry_add(imdr, id, size);
564
565 /* Fall back on large region allocation. */
566 if (e == NULL)
567 e = imdr_entry_add(&imd->lg, id, size);
568
569 return e;
570}
571
572const struct imd_entry *imd_entry_find(const struct imd *imd, uint32_t id)
573{
574 const struct imd_entry *e;
575
576 /* Many of the smaller allocations are used a lot. Therefore, try
577 * the small region first. */
578 e = imdr_entry_find(&imd->sm, id);
579
580 if (e == NULL)
581 e = imdr_entry_find(&imd->lg, id);
Aaron Durbin20686d82015-03-05 14:11:27 -0600582
583 return e;
584}
585
586const struct imd_entry *imd_entry_find_or_add(const struct imd *imd,
587 uint32_t id, size_t size)
588{
589 const struct imd_entry *e;
590
591 e = imd_entry_find(imd, id);
592
593 if (e != NULL)
594 return e;
595
596 return imd_entry_add(imd, id, size);
597}
598
599size_t imd_entry_size(const struct imd *imd, const struct imd_entry *entry)
600{
Aaron Durbincac50502015-03-24 23:14:46 -0500601 return imdr_entry_size(NULL, entry);
Aaron Durbin20686d82015-03-05 14:11:27 -0600602}
603
604void *imd_entry_at(const struct imd *imd, const struct imd_entry *entry)
605{
Aaron Durbincac50502015-03-24 23:14:46 -0500606 const struct imdr *imdr;
Aaron Durbin20686d82015-03-05 14:11:27 -0600607
Aaron Durbincac50502015-03-24 23:14:46 -0500608 imdr = imd_entry_to_imdr(imd, entry);
Aaron Durbin20686d82015-03-05 14:11:27 -0600609
Aaron Durbincac50502015-03-24 23:14:46 -0500610 if (imdr == NULL)
Aaron Durbin20686d82015-03-05 14:11:27 -0600611 return NULL;
612
Aaron Durbincac50502015-03-24 23:14:46 -0500613 return imdr_entry_at(imdr, entry);
Aaron Durbin20686d82015-03-05 14:11:27 -0600614}
615
Aaron Durbin1ca2d862015-09-30 12:26:54 -0500616uint32_t imd_entry_id(const struct imd *imd, const struct imd_entry *entry)
617{
618 return entry->id;
619}
620
Aaron Durbin20686d82015-03-05 14:11:27 -0600621int imd_entry_remove(const struct imd *imd, const struct imd_entry *entry)
622{
623 struct imd_root *r;
Aaron Durbincac50502015-03-24 23:14:46 -0500624 const struct imdr *imdr;
Aaron Durbin20686d82015-03-05 14:11:27 -0600625
Aaron Durbincac50502015-03-24 23:14:46 -0500626 imdr = imd_entry_to_imdr(imd, entry);
627
628 if (imdr == NULL)
Lee Leahy35af5c42017-03-09 17:35:28 -0800629 return -1;
Aaron Durbincac50502015-03-24 23:14:46 -0500630
631 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600632
633 if (r == NULL)
634 return -1;
635
636 if (root_is_locked(r))
637 return -1;
638
639 if (entry != root_last_entry(r))
640 return -1;
641
642 r->num_entries--;
643
644 return 0;
645}
646
Aaron Durbincac50502015-03-24 23:14:46 -0500647static void imdr_print_entries(const struct imdr *imdr, const char *indent,
648 const struct imd_lookup *lookup, size_t size)
Aaron Durbin20686d82015-03-05 14:11:27 -0600649{
650 struct imd_root *r;
651 size_t i;
652 size_t j;
653
Aaron Durbincac50502015-03-24 23:14:46 -0500654 if (imdr == NULL)
655 return;
Aaron Durbin20686d82015-03-05 14:11:27 -0600656
Aaron Durbincac50502015-03-24 23:14:46 -0500657 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600658
659 for (i = 0; i < r->num_entries; i++) {
660 const char *name = NULL;
661 const struct imd_entry *e = &r->entries[i];
662
663 for (j = 0; j < size; j++) {
664 if (lookup[j].id == e->id) {
665 name = lookup[j].name;
666 break;
667 }
668 }
669
Aaron Durbincac50502015-03-24 23:14:46 -0500670 printk(BIOS_DEBUG, "%s", indent);
671
Aaron Durbin20686d82015-03-05 14:11:27 -0600672 if (name == NULL)
673 printk(BIOS_DEBUG, "%08x ", e->id);
674 else
675 printk(BIOS_DEBUG, "%s", name);
676 printk(BIOS_DEBUG, "%2zu. ", i);
Aaron Durbincac50502015-03-24 23:14:46 -0500677 printk(BIOS_DEBUG, "%p ", imdr_entry_at(imdr, e));
Julius Werner540a9802019-12-09 13:03:29 -0800678 printk(BIOS_DEBUG, "0x%08zx\n", imdr_entry_size(imdr, e));
Aaron Durbincac50502015-03-24 23:14:46 -0500679 }
680}
681
682int imd_print_entries(const struct imd *imd, const struct imd_lookup *lookup,
683 size_t size)
684{
685 if (imdr_root(&imd->lg) == NULL)
686 return -1;
687
688 imdr_print_entries(&imd->lg, "", lookup, size);
689 if (imdr_root(&imd->sm) != NULL) {
690 printk(BIOS_DEBUG, "IMD small region:\n");
691 imdr_print_entries(&imd->sm, " ", lookup, size);
Aaron Durbin20686d82015-03-05 14:11:27 -0600692 }
693
694 return 0;
695}
Aaron Durbin1ca2d862015-09-30 12:26:54 -0500696
697int imd_cursor_init(const struct imd *imd, struct imd_cursor *cursor)
698{
699 if (imd == NULL || cursor == NULL)
700 return -1;
701
702 memset(cursor, 0, sizeof(*cursor));
703
704 cursor->imdr[0] = &imd->lg;
705 cursor->imdr[1] = &imd->sm;
706
707 return 0;
708}
709
710const struct imd_entry *imd_cursor_next(struct imd_cursor *cursor)
711{
712 struct imd_root *r;
713 const struct imd_entry *e;
714
715 if (cursor->current_imdr >= ARRAY_SIZE(cursor->imdr))
716 return NULL;
717
718 r = imdr_root(cursor->imdr[cursor->current_imdr]);
719
720 if (r == NULL)
721 return NULL;
722
723 if (cursor->current_entry >= r->num_entries) {
724 /* Try next imdr. */
725 cursor->current_imdr++;
726 cursor->current_entry = 0;
727 return imd_cursor_next(cursor);
728 }
729
730 e = &r->entries[cursor->current_entry];
731 cursor->current_entry++;
732
733 return e;
734}