Add bloblist_get_reg_conv() to get the register values for passing the
bloblist on according to the Firmware Handoff spec: the FDT address, the
signature and register conventions version, and the transfer list
address. It is the counterpart of bloblist_check_reg_conv(), which checks
these values when a bloblist is received, and shares its signature
calculation.

This allows U-Boot to pass its bloblist to the next stage in registers
instead of at a fixed address in memory.

Add a test that passes the values from bloblist_get_reg_conv() to
bloblist_check_reg_conv().

Signed-off-by: David Lechner <[email protected]>
---
 common/bloblist.c      | 36 +++++++++++++++++++++++++-----------
 include/bloblist.h     | 16 ++++++++++++++++
 test/common/bloblist.c | 24 ++++++++++++++++++++++++
 3 files changed, 65 insertions(+), 11 deletions(-)

diff --git a/common/bloblist.c b/common/bloblist.c
index 846c8047f74..4269a49ef99 100644
--- a/common/bloblist.c
+++ b/common/bloblist.c
@@ -664,22 +664,36 @@ int bloblist_init(void)
        return 0;
 }
 
-int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig, ulong xlist)
+static ulong bloblist_reg_conv_sig(void)
 {
        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));
-       }
+                       (IS_ENABLED(CONFIG_SPL_64BIT) && 
IS_ENABLED(CONFIG_SPL_BUILD)))
+               return ((BLOBLIST_MAGIC & ((1ULL << BLOBLIST_REGCONV_SHIFT_64) 
- 1)) |
+                       ((version  & BLOBLIST_REGCONV_MASK) << 
BLOBLIST_REGCONV_SHIFT_64));
+
+       return ((BLOBLIST_MAGIC & ((1UL << BLOBLIST_REGCONV_SHIFT_32) - 1)) |
+               ((version  & BLOBLIST_REGCONV_MASK) << 
BLOBLIST_REGCONV_SHIFT_32));
+}
+
+int bloblist_get_reg_conv(ulong *rfdt, ulong *rsig, ulong *xlist)
+{
+       if (!gd->bloblist)
+               return -ENOENT;
+
+       *rfdt = (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0);
+       *rsig = bloblist_reg_conv_sig();
+       *xlist = bloblist_get_base();
+
+       return 0;
+}
+
+int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig, ulong xlist)
+{
+       int ret;
 
-       if (rzero || rsig != sigval)
+       if (rzero || rsig != bloblist_reg_conv_sig())
                return -EIO;
 
        ret = bloblist_check(xlist, 0);
diff --git a/include/bloblist.h b/include/bloblist.h
index fcd290eeb16..cdb5764cf55 100644
--- a/include/bloblist.h
+++ b/include/bloblist.h
@@ -536,6 +536,22 @@ int bloblist_init(void);
  */
 int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig, ulong xlist);
 
+/**
+ * bloblist_get_reg_conv() - Get the register values for passing the bloblist
+ *                          according to the Firmware Handoff spec.
+ *
+ * This is the counterpart of bloblist_check_reg_conv(). The register that
+ * must be zero is not returned. Call bloblist_finish() before passing the
+ * bloblist on.
+ *
+ * @rfdt:  Returns the FDT base address, or 0 if there is no control FDT in
+ *        the bloblist.
+ * @rsig:  Returns the signature and register conventions version.
+ * @xlist: Returns the transfer list base address.
+ * Return: 0 if OK, -ENOENT if there is no bloblist.
+ */
+int bloblist_get_reg_conv(ulong *rfdt, ulong *rsig, ulong *xlist);
+
 /**
  * xferlist_from_boot_arg() - Get bloblist from the boot args.
  *
diff --git a/test/common/bloblist.c b/test/common/bloblist.c
index 797bde27025..23def33ab6f 100644
--- a/test/common/bloblist.c
+++ b/test/common/bloblist.c
@@ -605,3 +605,27 @@ static int bloblist_test_blob_maxsize(struct 
unit_test_state *uts)
        return 0;
 }
 BLOBLIST_TEST(bloblist_test_blob_maxsize, UFT_BLOBLIST);
+
+/* Test that the register values for passing a bloblist pass the check */
+static int bloblist_test_reg_conv(struct unit_test_state *uts)
+{
+       ulong rfdt, rsig, xlist;
+       void *fdt;
+
+       clear_bloblist();
+       ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0, 0));
+       fdt = bloblist_add(BLOBLISTT_CONTROL_FDT, TEST_SIZE, 0);
+       ut_assertnonnull(fdt);
+       ut_assertok(bloblist_finish());
+
+       ut_assertok(bloblist_get_reg_conv(&rfdt, &rsig, &xlist));
+       ut_asserteq((ulong)fdt, rfdt);
+       ut_asserteq(TEST_ADDR, xlist);
+       ut_assertok(bloblist_check_reg_conv(rfdt, 0, rsig, xlist));
+
+       ut_asserteq(-EIO, bloblist_check_reg_conv(rfdt, 1, rsig, xlist));
+       ut_asserteq(-EIO, bloblist_check_reg_conv(rfdt, 0, rsig + 1, xlist));
+
+       return 0;
+}
+BLOBLIST_TEST(bloblist_test_reg_conv, UFT_BLOBLIST);

-- 
2.53.0

Reply via email to