diff options
Diffstat (limited to 'common/bloblist.c')
-rw-r--r-- | common/bloblist.c | 116 |
1 files changed, 79 insertions, 37 deletions
diff --git a/common/bloblist.c b/common/bloblist.c index ad06d7a1795..6e4f020d7c4 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -6,7 +6,6 @@ #define LOG_CATEGORY LOGC_BLOBLIST -#include <common.h> #include <bloblist.h> #include <display_options.h> #include <log.h> @@ -224,13 +223,26 @@ static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size, void *bloblist_find(uint tag, int size) { + void *blob = NULL; + int blob_size; + + blob = bloblist_get_blob(tag, &blob_size); + + if (size && size != blob_size) + return NULL; + + return blob; +} + +void *bloblist_get_blob(uint tag, int *sizep) +{ struct bloblist_rec *rec; rec = bloblist_findrec(tag); if (!rec) return NULL; - if (size && size != rec->size) - return NULL; + + *sizep = rec->size; return (void *)rec + rec_hdr_size(rec); } @@ -476,6 +488,9 @@ int bloblist_reloc(void *to, uint to_size) { struct bloblist_hdr *hdr; + if (!to_size) + return 0; + if (to_size < gd->bloblist->total_size) return -ENOSPC; @@ -490,8 +505,7 @@ int bloblist_reloc(void *to, uint to_size) /* * Weak default function for getting bloblist from boot args. */ -int __weak xferlist_from_boot_arg(ulong __always_unused addr, - ulong __always_unused size) +int __weak xferlist_from_boot_arg(ulong __always_unused *addr) { return -ENOENT; } @@ -499,38 +513,46 @@ int __weak xferlist_from_boot_arg(ulong __always_unused addr, int bloblist_init(void) { bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED); - int ret = -ENOENT; - ulong addr, size; - /* - * If U-Boot is not in the first phase, an existing bloblist must be - * at a fixed address. - */ - bool from_addr = fixed && !u_boot_first_phase(); - /* - * If U-Boot is in the first phase that an arch custom routine should - * install the bloblist passed from previous loader to this fixed - * address. - */ - bool from_boot_arg = fixed && u_boot_first_phase(); + int ret = 0; + ulong addr = 0, size; + + /* Check if a valid transfer list passed in */ + if (!xferlist_from_boot_arg(&addr)) { + size = bloblist_get_total_size(); + } else { + /* + * If U-Boot is not in the first phase, an existing bloblist must + * be at a fixed address. + */ + bool from_addr = fixed && !xpl_is_first_phase(); - if (spl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST)) - from_addr = false; - if (fixed) - addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, - CONFIG_BLOBLIST_ADDR); - size = CONFIG_BLOBLIST_SIZE; + /* + * If Firmware Handoff is mandatory but no transfer list is + * observed, report it as an error. + */ + if (IS_ENABLED(CONFIG_BLOBLIST_PASSAGE_MANDATORY)) + return -ENOENT; - if (from_boot_arg) - ret = xferlist_from_boot_arg(addr, size); - else if (from_addr) - ret = bloblist_check(addr, size); + ret = -ENOENT; - if (ret) - log_warning("Bloblist at %lx not found (err=%d)\n", - addr, ret); - else - /* Get the real size */ - size = gd->bloblist->total_size; + if (xpl_prev_phase() == PHASE_TPL && + !IS_ENABLED(CONFIG_TPL_BLOBLIST)) + from_addr = false; + if (fixed) + addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, + CONFIG_BLOBLIST_ADDR); + size = CONFIG_BLOBLIST_SIZE; + + if (from_addr) + ret = bloblist_check(addr, size); + + if (ret) + log_warning("Bloblist at %lx not found (err=%d)\n", + addr, ret); + else + /* Get the real size */ + size = gd->bloblist->total_size; + } if (ret) { /* @@ -555,6 +577,7 @@ int bloblist_init(void) log_debug("Found existing bloblist size %lx at %lx\n", size, addr); } + if (ret) return log_msg_ret("ini", ret); gd->flags |= GD_FLG_BLOBLIST_READY; @@ -575,10 +598,29 @@ int bloblist_maybe_init(void) return 0; } -int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig) +int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig, ulong xlist) { - if (rzero || rsig != (BLOBLIST_MAGIC | BLOBLIST_REGCONV_VER) || - rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) { + u64 version = BLOBLIST_REGCONV_VER; + ulong sigval; + int ret; + + if ((IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_SPL_BUILD)) || + (IS_ENABLED(CONFIG_SPL_64BIT) && IS_ENABLED(CONFIG_SPL_BUILD))) { + sigval = ((BLOBLIST_MAGIC & ((1ULL << BLOBLIST_REGCONV_SHIFT_64) - 1)) | + ((version & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_64)); + } else { + sigval = ((BLOBLIST_MAGIC & ((1UL << BLOBLIST_REGCONV_SHIFT_32) - 1)) | + ((version & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_32)); + } + + if (rzero || rsig != sigval) + return -EIO; + + ret = bloblist_check(xlist, 0); + if (ret) + return ret; + + if (rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) { gd->bloblist = NULL; /* Reset the gd bloblist pointer */ return -EIO; } |