blob: 2fc6fac38cd9b48cd277247e58a019d43d7fa37d [file] [log] [blame]
Aaron Durbin20686d82015-03-05 14:11:27 -06001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2015 Google, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Aaron Durbin20686d82015-03-05 14:11:27 -060014 */
15
16#include <assert.h>
17#include <cbmem.h>
18#include <console/console.h>
19#include <imd.h>
20#include <stdlib.h>
21#include <string.h>
22
23/* For more details on implementation and usage please see the imd.h header. */
24
25static const uint32_t IMD_ROOT_PTR_MAGIC = 0xc0389481;
26static const uint32_t IMD_ENTRY_MAGIC = ~0xc0389481;
Aaron Durbincac50502015-03-24 23:14:46 -050027static const uint32_t SMALL_REGION_ID = CBMEM_ID_IMD_SMALL;
Aaron Durbin20686d82015-03-05 14:11:27 -060028static const size_t LIMIT_ALIGN = 4096;
29
30/* In-memory data structures. */
31struct imd_root_pointer {
32 uint32_t magic;
33 /* Relative to upper limit/offset. */
34 int32_t root_offset;
35} __attribute__((packed));
36
37struct imd_entry {
38 uint32_t magic;
39 /* start is located relative to imd_root */
40 int32_t start_offset;
41 uint32_t size;
42 uint32_t id;
43} __attribute__((packed));
44
45struct imd_root {
46 uint32_t max_entries;
47 uint32_t num_entries;
48 uint32_t flags;
49 uint32_t entry_align;
50 /* Used for fixing the size of an imd. Relative to the root. */
51 int32_t max_offset;
52 struct imd_entry entries[0];
53} __attribute__((packed));
54
55#define IMD_FLAG_LOCKED 1
56
57static void *relative_pointer(void *base, ssize_t offset)
58{
59 intptr_t b = (intptr_t)base;
60 b += offset;
61 return (void *)b;
62}
63
64static bool imd_root_pointer_valid(const struct imd_root_pointer *rp)
65{
66 return !!(rp->magic == IMD_ROOT_PTR_MAGIC);
67}
68
Aaron Durbincac50502015-03-24 23:14:46 -050069static struct imd_root *imdr_root(const struct imdr *imdr)
Aaron Durbin20686d82015-03-05 14:11:27 -060070{
Aaron Durbincac50502015-03-24 23:14:46 -050071 return imdr->r;
Aaron Durbin20686d82015-03-05 14:11:27 -060072}
73
74/*
75 * The root pointer is relative to the upper limit of the imd. i.e. It sits
76 * just below the upper limit.
77 */
Aaron Durbincac50502015-03-24 23:14:46 -050078static struct imd_root_pointer *imdr_get_root_pointer(const struct imdr *imdr)
Aaron Durbin20686d82015-03-05 14:11:27 -060079{
80 struct imd_root_pointer *rp;
81
Aaron Durbincac50502015-03-24 23:14:46 -050082 rp = relative_pointer((void *)imdr->limit, -sizeof(*rp));
Aaron Durbin20686d82015-03-05 14:11:27 -060083
84 return rp;
85}
86
87static void imd_link_root(struct imd_root_pointer *rp, struct imd_root *r)
88{
89 rp->magic = IMD_ROOT_PTR_MAGIC;
90 rp->root_offset = (int32_t)((intptr_t)r - (intptr_t)rp);
91}
92
Aaron Durbincac50502015-03-24 23:14:46 -050093static struct imd_entry *root_last_entry(struct imd_root *r)
94{
95 return &r->entries[r->num_entries - 1];
96}
97
98static size_t root_num_entries(size_t root_size)
99{
100 size_t entries_size;
101
102 entries_size = root_size;
103 entries_size -= sizeof(struct imd_root_pointer);
104 entries_size -= sizeof(struct imd_root);
105
106 return entries_size / sizeof(struct imd_entry);
107}
108
109static size_t imd_root_data_left(struct imd_root *r)
110{
111 struct imd_entry *last_entry;
112
113 last_entry = root_last_entry(r);
114
115 if (r->max_offset != 0)
116 return last_entry->start_offset - r->max_offset;
117
118 return ~(size_t)0;
119}
120
121static bool root_is_locked(const struct imd_root *r)
122{
123 return !!(r->flags & IMD_FLAG_LOCKED);
124}
125
Aaron Durbin20686d82015-03-05 14:11:27 -0600126static void imd_entry_assign(struct imd_entry *e, uint32_t id,
127 ssize_t offset, size_t size)
128{
129 e->magic = IMD_ENTRY_MAGIC;
130 e->start_offset = offset;
131 e->size = size;
132 e->id = id;
133}
134
Aaron Durbincac50502015-03-24 23:14:46 -0500135static void imdr_init(struct imdr *ir, void *upper_limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600136{
137 uintptr_t limit = (uintptr_t)upper_limit;
138 /* Upper limit is aligned down to 4KiB */
Aaron Durbincac50502015-03-24 23:14:46 -0500139 ir->limit = ALIGN_DOWN(limit, LIMIT_ALIGN);
140 ir->r = NULL;
Aaron Durbin20686d82015-03-05 14:11:27 -0600141}
142
Aaron Durbincac50502015-03-24 23:14:46 -0500143static int imdr_create_empty(struct imdr *imdr, size_t root_size,
144 size_t entry_align)
Aaron Durbin20686d82015-03-05 14:11:27 -0600145{
146 struct imd_root_pointer *rp;
147 struct imd_root *r;
148 struct imd_entry *e;
149 ssize_t root_offset;
Aaron Durbin20686d82015-03-05 14:11:27 -0600150
Aaron Durbincac50502015-03-24 23:14:46 -0500151 if (!imdr->limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600152 return -1;
153
154 /* root_size and entry_align should be a power of 2. */
155 assert(IS_POWER_OF_2(root_size));
156 assert(IS_POWER_OF_2(entry_align));
157
Aaron Durbincac50502015-03-24 23:14:46 -0500158 if (!imdr->limit)
159 return -1;
160
Aaron Durbin20686d82015-03-05 14:11:27 -0600161 /*
Martin Roth2ed0aa22016-01-05 20:58:58 -0700162 * root_size needs to be large enough to accommodate root pointer and
Aaron Durbin20686d82015-03-05 14:11:27 -0600163 * root book keeping structure. The caller needs to ensure there's
164 * enough room for tracking individual allocations.
165 */
166 if (root_size < (sizeof(*rp) + sizeof(*r)))
167 return -1;
168
169 /* For simplicity don't allow sizes or alignments to exceed LIMIT_ALIGN. */
170 if (root_size > LIMIT_ALIGN || entry_align > LIMIT_ALIGN)
171 return -1;
172
173 /* Additionally, don't handle an entry alignment > root_size. */
174 if (entry_align > root_size)
175 return -1;
176
Aaron Durbincac50502015-03-24 23:14:46 -0500177 rp = imdr_get_root_pointer(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600178
179 root_offset = -(ssize_t)root_size;
180 /* Set root pointer. */
Aaron Durbincac50502015-03-24 23:14:46 -0500181 imdr->r = relative_pointer((void *)imdr->limit, root_offset);
182 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600183 imd_link_root(rp, r);
184
185 memset(r, 0, sizeof(*r));
186 r->entry_align = entry_align;
187
188 /* Calculate size left for entries. */
Aaron Durbincac50502015-03-24 23:14:46 -0500189 r->max_entries = root_num_entries(root_size);
Aaron Durbin20686d82015-03-05 14:11:27 -0600190
191 /* Fill in first entry covering the root region. */
192 r->num_entries = 1;
193 e = &r->entries[0];
194 imd_entry_assign(e, CBMEM_ID_IMD_ROOT, 0, root_size);
195
196 printk(BIOS_DEBUG, "IMD: root @ %p %u entries.\n", r, r->max_entries);
197
198 return 0;
199}
200
Aaron Durbincac50502015-03-24 23:14:46 -0500201static int imdr_recover(struct imdr *imdr)
Aaron Durbin20686d82015-03-05 14:11:27 -0600202{
203 struct imd_root_pointer *rp;
204 struct imd_root *r;
205 uintptr_t low_limit;
206 size_t i;
207
Aaron Durbincac50502015-03-24 23:14:46 -0500208 if (!imdr->limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600209 return -1;
210
Aaron Durbincac50502015-03-24 23:14:46 -0500211 rp = imdr_get_root_pointer(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600212
213 if (!imd_root_pointer_valid(rp))
214 return -1;
215
216 r = relative_pointer(rp, rp->root_offset);
217
218 /* Confirm the root and root pointer are just under the limit. */
219 if (ALIGN_UP((uintptr_t)&r->entries[r->max_entries], LIMIT_ALIGN) !=
Aaron Durbincac50502015-03-24 23:14:46 -0500220 imdr->limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600221 return -1;
222
223 if (r->num_entries > r->max_entries)
224 return -1;
225
226 /* Entry alignment should be power of 2. */
227 if (!IS_POWER_OF_2(r->entry_align))
228 return -1;
229
230 low_limit = (uintptr_t)relative_pointer(r, r->max_offset);
231
232 /* If no max_offset then lowest limit is 0. */
233 if (low_limit == (uintptr_t)r)
234 low_limit = 0;
235
236 for (i = 0; i < r->num_entries; i++) {
237 uintptr_t start_addr;
238 const struct imd_entry *e = &r->entries[i];
239
240 if (e->magic != IMD_ENTRY_MAGIC)
241 return -1;
242
243 start_addr = (uintptr_t)relative_pointer(r, e->start_offset);
244 if (start_addr < low_limit)
245 return -1;
Aaron Durbincac50502015-03-24 23:14:46 -0500246 if (start_addr >= imdr->limit ||
247 (start_addr + e->size) > imdr->limit)
Aaron Durbin20686d82015-03-05 14:11:27 -0600248 return -1;
249 }
250
251 /* Set root pointer. */
Aaron Durbincac50502015-03-24 23:14:46 -0500252 imdr->r = r;
Aaron Durbin20686d82015-03-05 14:11:27 -0600253
254 return 0;
255}
256
Aaron Durbincac50502015-03-24 23:14:46 -0500257static const struct imd_entry *imdr_entry_find(const struct imdr *imdr,
258 uint32_t id)
Aaron Durbin20686d82015-03-05 14:11:27 -0600259{
260 struct imd_root *r;
261 struct imd_entry *e;
Aaron Durbincac50502015-03-24 23:14:46 -0500262 size_t i;
Aaron Durbin20686d82015-03-05 14:11:27 -0600263
Aaron Durbincac50502015-03-24 23:14:46 -0500264 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600265
Aaron Durbincac50502015-03-24 23:14:46 -0500266 if (r == NULL)
267 return NULL;
Aaron Durbin20686d82015-03-05 14:11:27 -0600268
Aaron Durbincac50502015-03-24 23:14:46 -0500269 e = NULL;
270 /* Skip first entry covering the root. */
271 for (i = 1; i < r->num_entries; i++) {
272 if (id != r->entries[i].id)
273 continue;
274 e = &r->entries[i];
275 break;
276 }
277
278 return e;
279}
280
281static int imdr_limit_size(struct imdr *imdr, size_t max_size)
282{
283 struct imd_root *r;
284 ssize_t smax_size;
285 size_t root_size;
286
287 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600288 if (r == NULL)
289 return -1;
290
Aaron Durbincac50502015-03-24 23:14:46 -0500291 root_size = imdr->limit - (uintptr_t)r;
Aaron Durbin20686d82015-03-05 14:11:27 -0600292
Aaron Durbincac50502015-03-24 23:14:46 -0500293 if (max_size < root_size)
294 return -1;
Aaron Durbin20686d82015-03-05 14:11:27 -0600295
Aaron Durbincac50502015-03-24 23:14:46 -0500296 /* Take into account the root size. */
297 smax_size = max_size - root_size;
298 smax_size = -smax_size;
Aaron Durbin20686d82015-03-05 14:11:27 -0600299
Aaron Durbincac50502015-03-24 23:14:46 -0500300 r->max_offset = smax_size;
Aaron Durbin20686d82015-03-05 14:11:27 -0600301
302 return 0;
303}
304
Aaron Durbincac50502015-03-24 23:14:46 -0500305static size_t imdr_entry_size(const struct imdr *imdr,
306 const struct imd_entry *e)
307{
308 return e->size;
309}
310
311static void *imdr_entry_at(const struct imdr *imdr, const struct imd_entry *e)
312{
313 return relative_pointer(imdr_root(imdr), e->start_offset);
314}
315
Aaron Durbin20686d82015-03-05 14:11:27 -0600316static struct imd_entry *imd_entry_add_to_root(struct imd_root *r, uint32_t id,
317 size_t size)
318{
319 struct imd_entry *entry;
320 struct imd_entry *last_entry;
321 ssize_t e_offset;
322 size_t used_size;
323
324 if (r->num_entries == r->max_entries)
325 return NULL;
326
327 /* Determine total size taken up by entry. */
328 used_size = ALIGN_UP(size, r->entry_align);
329
Aaron Durbin20686d82015-03-05 14:11:27 -0600330 /* See if size overflows imd total size. */
Aaron Durbincac50502015-03-24 23:14:46 -0500331 if (used_size > imd_root_data_left(r))
332 return NULL;
Aaron Durbin20686d82015-03-05 14:11:27 -0600333
334 /*
335 * Determine if offset field overflows. All offsets should be lower
336 * than the previous one.
337 */
Aaron Durbincac50502015-03-24 23:14:46 -0500338 last_entry = root_last_entry(r);
Aaron Durbin20686d82015-03-05 14:11:27 -0600339 e_offset = last_entry->start_offset;
340 e_offset -= (ssize_t)used_size;
341 if (e_offset > last_entry->start_offset)
342 return NULL;
343
344 entry = root_last_entry(r) + 1;
345 r->num_entries++;
346
347 imd_entry_assign(entry, id, e_offset, size);
348
349 return entry;
350}
351
Aaron Durbincac50502015-03-24 23:14:46 -0500352static const struct imd_entry *imdr_entry_add(const struct imdr *imdr,
353 uint32_t id, size_t size)
Aaron Durbin20686d82015-03-05 14:11:27 -0600354{
355 struct imd_root *r;
356
Aaron Durbincac50502015-03-24 23:14:46 -0500357 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600358
359 if (r == NULL)
360 return NULL;
361
362 if (root_is_locked(r))
363 return NULL;
364
365 return imd_entry_add_to_root(r, id, size);
366}
367
Aaron Durbincac50502015-03-24 23:14:46 -0500368static bool imdr_has_entry(const struct imdr *imdr, const struct imd_entry *e)
369{
370 struct imd_root *r;
371 size_t idx;
372
373 r = imdr_root(imdr);
374 if (r == NULL)
375 return false;
376
377 /* Determine if the entry is within this root structure. */
378 idx = e - &r->entries[0];
379 if (idx >= r->num_entries)
380 return false;
381
382 return true;
383}
384
385static const struct imdr *imd_entry_to_imdr(const struct imd *imd,
386 const struct imd_entry *entry)
387{
388 if (imdr_has_entry(&imd->lg, entry))
389 return &imd->lg;
390
391 if (imdr_has_entry(&imd->sm, entry))
392 return &imd->sm;
393
394 return NULL;
395}
396
397/* Initialize imd handle. */
398void imd_handle_init(struct imd *imd, void *upper_limit)
399{
400 imdr_init(&imd->lg, upper_limit);
401 imdr_init(&imd->sm, NULL);
402}
403
404void imd_handle_init_partial_recovery(struct imd *imd)
405{
406 const struct imd_entry *e;
407 struct imd_root_pointer *rp;
408 struct imdr *imdr;
409
Aaron Durbin01562b62015-05-11 14:19:37 -0500410 if (imd->lg.limit == 0)
411 return;
412
Aaron Durbincac50502015-03-24 23:14:46 -0500413 imd_handle_init(imd, (void *)imd->lg.limit);
414
415 /* Initialize root pointer for the large regions. */
416 imdr = &imd->lg;
417 rp = imdr_get_root_pointer(imdr);
418 imdr->r = relative_pointer(rp, rp->root_offset);
419
420 e = imdr_entry_find(imdr, SMALL_REGION_ID);
421
422 if (e == NULL)
423 return;
424
425 imd->sm.limit = (uintptr_t)imdr_entry_at(imdr, e);
426 imd->sm.limit += imdr_entry_size(imdr, e);
427 imdr = &imd->sm;
428 rp = imdr_get_root_pointer(imdr);
429 imdr->r = relative_pointer(rp, rp->root_offset);
430}
431
432int imd_create_empty(struct imd *imd, size_t root_size, size_t entry_align)
433{
434 return imdr_create_empty(&imd->lg, root_size, entry_align);
435}
436
437int imd_create_tiered_empty(struct imd *imd,
438 size_t lg_root_size, size_t lg_entry_align,
439 size_t sm_root_size, size_t sm_entry_align)
440{
441 size_t sm_region_size;;
442 const struct imd_entry *e;
443 struct imdr *imdr;
444
445 imdr = &imd->lg;
446
447 if (imdr_create_empty(imdr, lg_root_size, lg_entry_align) != 0)
448 return -1;
449
450 /* Calculate the size of the small region to request. */
451 sm_region_size = root_num_entries(sm_root_size) * sm_entry_align;
452 sm_region_size += sm_root_size;
453 sm_region_size = ALIGN_UP(sm_region_size, lg_entry_align);
454
455 /* Add a new entry to the large region to cover the root and entries. */
456 e = imdr_entry_add(imdr, SMALL_REGION_ID, sm_region_size);
457
458 if (e == NULL)
459 goto fail;
460
461 imd->sm.limit = (uintptr_t)imdr_entry_at(imdr, e);
462 imd->sm.limit += sm_region_size;
463
464 if (imdr_create_empty(&imd->sm, sm_root_size, sm_entry_align) != 0 ||
465 imdr_limit_size(&imd->sm, sm_region_size))
466 goto fail;
467
468 return 0;
469fail:
470 imd_handle_init(imd, (void *)imdr->limit);
471 return -1;
472}
473
474int imd_recover(struct imd *imd)
475{
476 const struct imd_entry *e;
477 uintptr_t small_upper_limit;
478 struct imdr *imdr;
479
480 imdr = &imd->lg;
481 if (imdr_recover(imdr) != 0)
482 return -1;
483
484 /* Determine if small region is region is present. */
485 e = imdr_entry_find(imdr, SMALL_REGION_ID);
486
487 if (e == NULL)
488 return 0;
489
490 small_upper_limit = (uintptr_t)imdr_entry_at(imdr, e);
491 small_upper_limit += imdr_entry_size(imdr, e);
492
493 imd->sm.limit = small_upper_limit;
494
495 /* Tear down any changes on failure. */
496 if (imdr_recover(&imd->sm) != 0) {
497 imd_handle_init(imd, (void *)imd->lg.limit);
498 return -1;
499 }
500
501 return 0;
502}
503
504int imd_limit_size(struct imd *imd, size_t max_size)
505{
506 return imdr_limit_size(&imd->lg, max_size);
507}
508
509int imd_lockdown(struct imd *imd)
510{
511 struct imd_root *r;
512
513 r = imdr_root(&imd->lg);
514 if (r == NULL)
515 return -1;
516
517 r->flags |= IMD_FLAG_LOCKED;
518
519 r = imdr_root(&imd->sm);
520 if (r != NULL)
521 r->flags |= IMD_FLAG_LOCKED;
522
523 return 0;
524}
525
526int imd_region_used(struct imd *imd, void **base, size_t *size)
Aaron Durbin20686d82015-03-05 14:11:27 -0600527{
528 struct imd_root *r;
529 struct imd_entry *e;
Aaron Durbincac50502015-03-24 23:14:46 -0500530 void *low_addr;
531 size_t sz_used;
Aaron Durbin20686d82015-03-05 14:11:27 -0600532
Aaron Durbincac50502015-03-24 23:14:46 -0500533 if (!imd->lg.limit)
534 return -1;
535
536 r = imdr_root(&imd->lg);
Aaron Durbin20686d82015-03-05 14:11:27 -0600537
538 if (r == NULL)
Aaron Durbincac50502015-03-24 23:14:46 -0500539 return -1;
Aaron Durbin20686d82015-03-05 14:11:27 -0600540
Aaron Durbincac50502015-03-24 23:14:46 -0500541 /* Use last entry to obtain lowest address. */
542 e = root_last_entry(r);
543
544 low_addr = relative_pointer(r, e->start_offset);
545
546 /* Total size used is the last entry's base up to the limit. */
547 sz_used = imd->lg.limit - (uintptr_t)low_addr;
548
549 *base = low_addr;
550 *size = sz_used;
551
552 return 0;
553}
554
555const struct imd_entry *imd_entry_add(const struct imd *imd, uint32_t id,
556 size_t size)
557{
558 struct imd_root *r;
559 const struct imdr *imdr;
560 const struct imd_entry *e = NULL;
561
562 /*
563 * Determine if requested size is less than 1/4 of small data
564 * region is left.
565 */
566 imdr = &imd->sm;
567 r = imdr_root(imdr);
568
569 /* No small region. Use the large region. */
570 if (r == NULL)
571 return imdr_entry_add(&imd->lg, id, size);
572 else if (size <= r->entry_align || size <= imd_root_data_left(r) / 4)
573 e = imdr_entry_add(imdr, id, size);
574
575 /* Fall back on large region allocation. */
576 if (e == NULL)
577 e = imdr_entry_add(&imd->lg, id, size);
578
579 return e;
580}
581
582const struct imd_entry *imd_entry_find(const struct imd *imd, uint32_t id)
583{
584 const struct imd_entry *e;
585
586 /* Many of the smaller allocations are used a lot. Therefore, try
587 * the small region first. */
588 e = imdr_entry_find(&imd->sm, id);
589
590 if (e == NULL)
591 e = imdr_entry_find(&imd->lg, id);
Aaron Durbin20686d82015-03-05 14:11:27 -0600592
593 return e;
594}
595
596const struct imd_entry *imd_entry_find_or_add(const struct imd *imd,
597 uint32_t id, size_t size)
598{
599 const struct imd_entry *e;
600
601 e = imd_entry_find(imd, id);
602
603 if (e != NULL)
604 return e;
605
606 return imd_entry_add(imd, id, size);
607}
608
609size_t imd_entry_size(const struct imd *imd, const struct imd_entry *entry)
610{
Aaron Durbincac50502015-03-24 23:14:46 -0500611 return imdr_entry_size(NULL, entry);
Aaron Durbin20686d82015-03-05 14:11:27 -0600612}
613
614void *imd_entry_at(const struct imd *imd, const struct imd_entry *entry)
615{
Aaron Durbincac50502015-03-24 23:14:46 -0500616 const struct imdr *imdr;
Aaron Durbin20686d82015-03-05 14:11:27 -0600617
Aaron Durbincac50502015-03-24 23:14:46 -0500618 imdr = imd_entry_to_imdr(imd, entry);
Aaron Durbin20686d82015-03-05 14:11:27 -0600619
Aaron Durbincac50502015-03-24 23:14:46 -0500620 if (imdr == NULL)
Aaron Durbin20686d82015-03-05 14:11:27 -0600621 return NULL;
622
Aaron Durbincac50502015-03-24 23:14:46 -0500623 return imdr_entry_at(imdr, entry);
Aaron Durbin20686d82015-03-05 14:11:27 -0600624}
625
Aaron Durbin1ca2d862015-09-30 12:26:54 -0500626uint32_t imd_entry_id(const struct imd *imd, const struct imd_entry *entry)
627{
628 return entry->id;
629}
630
Aaron Durbin20686d82015-03-05 14:11:27 -0600631int imd_entry_remove(const struct imd *imd, const struct imd_entry *entry)
632{
633 struct imd_root *r;
Aaron Durbincac50502015-03-24 23:14:46 -0500634 const struct imdr *imdr;
Aaron Durbin20686d82015-03-05 14:11:27 -0600635
Aaron Durbincac50502015-03-24 23:14:46 -0500636 imdr = imd_entry_to_imdr(imd, entry);
637
638 if (imdr == NULL)
639 return - 1;
640
641 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600642
643 if (r == NULL)
644 return -1;
645
646 if (root_is_locked(r))
647 return -1;
648
649 if (entry != root_last_entry(r))
650 return -1;
651
652 r->num_entries--;
653
654 return 0;
655}
656
Aaron Durbincac50502015-03-24 23:14:46 -0500657static void imdr_print_entries(const struct imdr *imdr, const char *indent,
658 const struct imd_lookup *lookup, size_t size)
Aaron Durbin20686d82015-03-05 14:11:27 -0600659{
660 struct imd_root *r;
661 size_t i;
662 size_t j;
663
Aaron Durbincac50502015-03-24 23:14:46 -0500664 if (imdr == NULL)
665 return;
Aaron Durbin20686d82015-03-05 14:11:27 -0600666
Aaron Durbincac50502015-03-24 23:14:46 -0500667 r = imdr_root(imdr);
Aaron Durbin20686d82015-03-05 14:11:27 -0600668
669 for (i = 0; i < r->num_entries; i++) {
670 const char *name = NULL;
671 const struct imd_entry *e = &r->entries[i];
672
673 for (j = 0; j < size; j++) {
674 if (lookup[j].id == e->id) {
675 name = lookup[j].name;
676 break;
677 }
678 }
679
Aaron Durbincac50502015-03-24 23:14:46 -0500680 printk(BIOS_DEBUG, "%s", indent);
681
Aaron Durbin20686d82015-03-05 14:11:27 -0600682 if (name == NULL)
683 printk(BIOS_DEBUG, "%08x ", e->id);
684 else
685 printk(BIOS_DEBUG, "%s", name);
686 printk(BIOS_DEBUG, "%2zu. ", i);
Aaron Durbincac50502015-03-24 23:14:46 -0500687 printk(BIOS_DEBUG, "%p ", imdr_entry_at(imdr, e));
688 printk(BIOS_DEBUG, "%08zx\n", imdr_entry_size(imdr, e));
689 }
690}
691
692int imd_print_entries(const struct imd *imd, const struct imd_lookup *lookup,
693 size_t size)
694{
695 if (imdr_root(&imd->lg) == NULL)
696 return -1;
697
698 imdr_print_entries(&imd->lg, "", lookup, size);
699 if (imdr_root(&imd->sm) != NULL) {
700 printk(BIOS_DEBUG, "IMD small region:\n");
701 imdr_print_entries(&imd->sm, " ", lookup, size);
Aaron Durbin20686d82015-03-05 14:11:27 -0600702 }
703
704 return 0;
705}
Aaron Durbin1ca2d862015-09-30 12:26:54 -0500706
707int imd_cursor_init(const struct imd *imd, struct imd_cursor *cursor)
708{
709 if (imd == NULL || cursor == NULL)
710 return -1;
711
712 memset(cursor, 0, sizeof(*cursor));
713
714 cursor->imdr[0] = &imd->lg;
715 cursor->imdr[1] = &imd->sm;
716
717 return 0;
718}
719
720const struct imd_entry *imd_cursor_next(struct imd_cursor *cursor)
721{
722 struct imd_root *r;
723 const struct imd_entry *e;
724
725 if (cursor->current_imdr >= ARRAY_SIZE(cursor->imdr))
726 return NULL;
727
728 r = imdr_root(cursor->imdr[cursor->current_imdr]);
729
730 if (r == NULL)
731 return NULL;
732
733 if (cursor->current_entry >= r->num_entries) {
734 /* Try next imdr. */
735 cursor->current_imdr++;
736 cursor->current_entry = 0;
737 return imd_cursor_next(cursor);
738 }
739
740 e = &r->entries[cursor->current_entry];
741 cursor->current_entry++;
742
743 return e;
744}