summaryrefslogtreecommitdiff
path: root/common/bloblist.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/bloblist.c')
-rw-r--r--common/bloblist.c120
1 files changed, 102 insertions, 18 deletions
diff --git a/common/bloblist.c b/common/bloblist.c
index 99501951e0..33b5862380 100644
--- a/common/bloblist.c
+++ b/common/bloblist.c
@@ -11,17 +11,47 @@
#include <spl.h>
#include <u-boot/crc.h>
+/*
+ * A bloblist is a single contiguous chunk of memory with a header
+ * (struct bloblist_hdr) and a number of blobs in it.
+ *
+ * Each blob starts on a BLOBLIST_ALIGN boundary relative to the start of the
+ * bloblist and consists of a struct bloblist_rec, some padding to the required
+ * alignment for the blog and then the actual data. The padding ensures that the
+ * start address of the data in each blob is aligned as required. Note that
+ * each blob's *data* is aligned to BLOBLIST_ALIGN regardless of the alignment
+ * of the bloblist itself or the blob header.
+ *
+ * So far, only BLOBLIST_ALIGN alignment is supported.
+ */
+
DECLARE_GLOBAL_DATA_PTR;
-struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
+static const char *const tag_name[] = {
+ [BLOBLISTT_NONE] = "(none)",
+ [BLOBLISTT_EC_HOSTEVENT] = "EC host event",
+ [BLOBLISTT_SPL_HANDOFF] = "SPL hand-off",
+ [BLOBLISTT_VBOOT_CTX] = "Chrome OS vboot context",
+ [BLOBLISTT_VBOOT_HANDOFF] = "Chrome OS vboot hand-off",
+};
+
+const char *bloblist_tag_name(enum bloblist_tag_t tag)
+{
+ if (tag < 0 || tag >= BLOBLISTT_COUNT)
+ return "invalid";
+
+ return tag_name[tag];
+}
+
+static struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
{
if (hdr->alloced <= hdr->hdr_size)
return NULL;
return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
}
-struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
- struct bloblist_rec *rec)
+static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
+ struct bloblist_rec *rec)
{
ulong offset;
@@ -53,13 +83,25 @@ static struct bloblist_rec *bloblist_findrec(uint tag)
return NULL;
}
-static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp)
+static int bloblist_addrec(uint tag, int size, int align,
+ struct bloblist_rec **recp)
{
struct bloblist_hdr *hdr = gd->bloblist;
struct bloblist_rec *rec;
- int new_alloced;
+ int data_start, new_alloced;
+
+ if (!align)
+ align = BLOBLIST_ALIGN;
+
+ /* Figure out where the new data will start */
+ data_start = map_to_sysmem(hdr) + hdr->alloced + sizeof(*rec);
+
+ /* Align the address and then calculate the offset from ->alloced */
+ data_start = ALIGN(data_start, align) - map_to_sysmem(hdr);
+
+ /* Calculate the new allocated total */
+ new_alloced = data_start + ALIGN(size, align);
- new_alloced = hdr->alloced + sizeof(*rec) + ALIGN(size, BLOBLIST_ALIGN);
if (new_alloced >= hdr->size) {
log(LOGC_BLOBLIST, LOGL_ERR,
"Failed to allocate %x bytes size=%x, need size=%x\n",
@@ -67,21 +109,23 @@ static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp)
return log_msg_ret("bloblist add", -ENOSPC);
}
rec = (void *)hdr + hdr->alloced;
- hdr->alloced = new_alloced;
rec->tag = tag;
- rec->hdr_size = sizeof(*rec);
+ rec->hdr_size = data_start - hdr->alloced;
rec->size = size;
rec->spare = 0;
/* Zero the record data */
- memset(rec + 1, '\0', rec->size);
+ memset((void *)rec + rec->hdr_size, '\0', rec->size);
+
+ hdr->alloced = new_alloced;
*recp = rec;
return 0;
}
-static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size)
+static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size,
+ int align)
{
struct bloblist_rec *rec;
@@ -94,7 +138,7 @@ static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size)
} else {
int ret;
- ret = bloblist_addrec(tag, size, &rec);
+ ret = bloblist_addrec(tag, size, align, &rec);
if (ret)
return ret;
}
@@ -116,22 +160,22 @@ void *bloblist_find(uint tag, int size)
return (void *)rec + rec->hdr_size;
}
-void *bloblist_add(uint tag, int size)
+void *bloblist_add(uint tag, int size, int align)
{
struct bloblist_rec *rec;
- if (bloblist_addrec(tag, size, &rec))
+ if (bloblist_addrec(tag, size, align, &rec))
return NULL;
- return rec + 1;
+ return (void *)rec + rec->hdr_size;
}
-int bloblist_ensure_size(uint tag, int size, void **blobp)
+int bloblist_ensure_size(uint tag, int size, int align, void **blobp)
{
struct bloblist_rec *rec;
int ret;
- ret = bloblist_ensurerec(tag, &rec, size);
+ ret = bloblist_ensurerec(tag, &rec, size, align);
if (ret)
return ret;
*blobp = (void *)rec + rec->hdr_size;
@@ -143,7 +187,7 @@ void *bloblist_ensure(uint tag, int size)
{
struct bloblist_rec *rec;
- if (bloblist_ensurerec(tag, &rec, size))
+ if (bloblist_ensurerec(tag, &rec, size, 0))
return NULL;
return (void *)rec + rec->hdr_size;
@@ -154,7 +198,7 @@ int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp)
struct bloblist_rec *rec;
int ret;
- ret = bloblist_ensurerec(tag, &rec, *sizep);
+ ret = bloblist_ensurerec(tag, &rec, *sizep, 0);
if (ret == -ESPIPE)
*sizep = rec->size;
else if (ret)
@@ -233,6 +277,46 @@ int bloblist_finish(void)
return 0;
}
+void bloblist_get_stats(ulong *basep, ulong *sizep, ulong *allocedp)
+{
+ struct bloblist_hdr *hdr = gd->bloblist;
+
+ *basep = map_to_sysmem(gd->bloblist);
+ *sizep = hdr->size;
+ *allocedp = hdr->alloced;
+}
+
+static void show_value(const char *prompt, ulong value)
+{
+ printf("%s:%*s %-5lx ", prompt, 8 - (int)strlen(prompt), "", value);
+ print_size(value, "\n");
+}
+
+void bloblist_show_stats(void)
+{
+ ulong base, size, alloced;
+
+ bloblist_get_stats(&base, &size, &alloced);
+ printf("base: %lx\n", base);
+ show_value("size", size);
+ show_value("alloced", alloced);
+ show_value("free", size - alloced);
+}
+
+void bloblist_show_list(void)
+{
+ struct bloblist_hdr *hdr = gd->bloblist;
+ struct bloblist_rec *rec;
+
+ printf("%-8s %8s Tag Name\n", "Address", "Size");
+ for (rec = bloblist_first_blob(hdr); rec;
+ rec = bloblist_next_blob(hdr, rec)) {
+ printf("%08lx %8x %3d %s\n",
+ (ulong)map_to_sysmem((void *)rec + rec->hdr_size),
+ rec->size, rec->tag, bloblist_tag_name(rec->tag));
+ }
+}
+
int bloblist_init(void)
{
bool expected;