[U-Boot] passing info from SPL to U-Boot
Heiko Schocher
hs at denx.de
Fri Mar 15 05:36:23 UTC 2019
Hello Simon,
Am 14.03.2019 um 11:02 schrieb Simon Glass:
> Hi Heiko,
>
> On Tue, 12 Mar 2019 at 02:50, Heiko Schocher <hs at denx.de> wrote:
>>
>> Hello Simon, Tom,
>>
>> Am 12.03.2019 um 09:21 schrieb Heiko Schocher:
>>> Hello Simon, Tom,
>>>
>>> I am just stumbeld on an am437x basd board over the problem to pass
>>> the bootmode from SPL to U-Boot. On am437x the bootmode info get
>>> overwritten from SPL stack, and I need this info in U-Boot.
>>>
>>> Hack would be to move SPL stack to another address, but we loose
>>> than 0xa000 size for stack ... I do not want to go this way..
>>>
>>> I thought gd info is passed from SPL to U-Boot, but this is not the case!
>>>
>>> Looking into
>>>
>>> ...
>>> 75 bic r0, r0, #7 /* 8-byte alignment for ABI compliance */
>>> 76 mov sp, r0
>>> 77 bl board_init_f_alloc_reserve
>>> 78 mov sp, r0
>>> 79 /* set up gd here, outside any C code */
>>> 80 mov r9, r0
>>> 81 bl board_init_f_init_reserve
>>>
>>> and common/init/board_init.c:
>>>
>>> 99 void board_init_f_init_reserve(ulong base)
>>> 100 {
>>> 101 struct global_data *gd_ptr;
>>> 102
>>> 103 /*
>>> 104 * clear GD entirely and set it up.
>>> 105 * Use gd_ptr, as gd may not be properly set yet.
>>> 106 */
>>> 107
>>> 108 gd_ptr = (struct global_data *)base;
>>> 109 /* zero the area */
>>> 110 memset(gd_ptr, '\0', sizeof(*gd));
>>> 111 /* set GD unless architecture did it already */
>>> 112 #if !defined(CONFIG_ARM)
>>> 113 arch_setup_gd(gd_ptr);
>>> 114 #endif
>>>
>>> gd is always initialized with zeros, no chance for passing infos from
>>> SPL to U-Boot...
>>>
>>> I really thought, that gd_t was intentionally designed for passing data
>>> between different U-Boot states, but looking into gd_t definiton in
>>> include/asm-generic/global_data.h it is a big ifdef mess and not useable
>>> as an "API" between TPL/SPL and U-Boot ...
>>>
>>> I thought also, that SPL detects for example ramsize and than passes
>>> this info to U-Boot ...
>>>
>>> But Ok, I found "common/init/handoff.c" which seems now the way to go, but:
>>>
>>> ./common/board_f.c
>>>
>>> 281 static int setup_spl_handoff(void)
>>> 282 {
>>> 283 #if CONFIG_IS_ENABLED(HANDOFF)
>>> 284 gd->spl_handoff = bloblist_find(BLOBLISTT_SPL_HANDOFF,
>>> 285 sizeof(struct spl_handoff));
>>> 286 debug("Found SPL hand-off info %p\n", gd->spl_handoff);
>>> 287 #endif
>>> 288
>>> 289 return 0;
>>> 290 }
>>>
>>> There is gd->spl_handoff used ... how could this work at least on arm,
>>> if gd is set to zeros on init ?
>>>
>>> Do I miss something obvious?
>>
>> Sorry for being so stupid, with:
>>
>> common/board_f.c
>>
>> 853 #ifdef CONFIG_BLOBLIST
>> 854 bloblist_init,
>> 855 #endif
>> 856 setup_spl_handoff,
>>
>> and common/bloblist.c
>>
>> 216 int bloblist_init(void)
>> 217 {
>> 218 bool expected;
>> 219 int ret = -ENOENT;
>> 220
>> 221 /**
>> 222 * Wed expect to find an existing bloblist in the first phase of U-Boot
>> 223 * that runs
>> 224 */
>> 225 expected = !u_boot_first_phase();
>> 226 if (expected)
>> 227 ret = bloblist_check(CONFIG_BLOBLIST_ADDR,
>> 228 CONFIG_BLOBLIST_SIZE);
>>
>> gd->spl_handoff gets setup through bloblist_find() ...
>>
>> But beside sandbox there is no current user currently, or?
>>
>> $ grep -lr BLOBLIST_ADDR .
>> ./test/bloblist.c
>> ./include/bloblist.h
>> ./common/bloblist.c
>> ./common/Kconfig
>> ./board/sandbox/README.sandbox
>> $
>
> Yes that's right, it is not used outside sandbox, although there are
> patches to use it on x86.
Thanks for clarifying!
> I think it is a reasonable idea to allow the gd region to pass from
> TPL -> SPL -> U-Boot. But we'll need to remove use of
> CONFIG_IS_ENABLED(), or put shared things at the beginning of the
> structure.
I thought about putting interchangeable things at the beginning
of gd_t.
The big advantage of a bloblist is, that you only need to parse it
and you know, what values are really setup from the previous stage.
Passing structs is not ideal, but small ... but may error prone?
Can we always be sure, previous stage sets up all info in gd_t
next stage expects?
> We need the concept of 'am I the first thing to run'. This is
> implemented in bloblist as u_boot_first_phase() - see spl.h. If this
> is true, we must set up the data structure. If false we must find one
> set up by a previous phase and use it. Bloblist handles this, but
> perhaps gd could as well?
Yes, this could be used.
> Also consider the scenario where there is a read-only TPL programmed
> in manufacture that never changes, and a read-write SPL + U-Boot that
> can be upgraded in the field. In this case they may eventually end up
> being built with different versions of U-Boot. The bloblist structure
> is intended to handle this by at least checking that the size matches.
Just experimenting with:
diff --git a/common/init/board_init.c b/common/init/board_init.c
index 526fee35ff..bdb4b6364d 100644
--- a/common/init/board_init.c
+++ b/common/init/board_init.c
@@ -96,9 +96,10 @@ ulong board_init_f_alloc_reserve(ulong top)
* (seemingly useless) incrementation causes no code increase.
*/
-void board_init_f_init_reserve(ulong base)
+void board_init_f_init_reserve(ulong base, ulong oldgd)
{
struct global_data *gd_ptr;
+ struct global_data *gd_ptr_old;
/*
* clear GD entirely and set it up.
@@ -106,8 +107,22 @@ void board_init_f_init_reserve(ulong base)
*/
gd_ptr = (struct global_data *)base;
- /* zero the area */
- memset(gd_ptr, '\0', sizeof(*gd));
+ gd_ptr_old = (struct global_data *)oldgd;
+ if (u_boot_first_phase() ||
+ oldgd == 0 ||
+ !(((gd_ptr->magic == UBOOT_GD_MAGIC) &&
+ (gd_ptr->gd_size == sizeof(struct global_data))))) {
+ /* setup gd, zero the area ... */
+ memset(gd_ptr, '\0', sizeof(*gd));
+ /* ... and set magic and size information */
+ gd_ptr->magic = UBOOT_GD_MAGIC;
+ gd_ptr->gd_size = sizeof(struct global_data);
+ } else {
+ /*
+ * in case we get an already initialised gd_pointer
+ * use the info from already existing oldgd.
+ */
+ }
/* set GD unless architecture did it already */
#if !defined(CONFIG_ARM)
arch_setup_gd(gd_ptr);
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 78dcf40bff..3a5063dbe1 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -23,8 +23,11 @@
#include <membuff.h>
#include <linux/list.h>
+#define UBOOT_GD_MAGIC 0x19730517
typedef struct global_data {
bd_t *bd;
+ unsigned long magic;
+ int gd_size;
unsigned long flags;
unsigned int baudrate;
unsigned long cpu_clk; /* CPU clock in Hz! */
(after moving u_boot_first_phase() to include/common.h)
But it is WIP, nothing functional yet...
> Related, I feel that we should figure out how to use registers to pass
> addresses from SPL to U-Boot. On ARM we could use r0 to pass the value
> of gd, perhaps.
Perhaps, yes.
bye,
Heiko
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-52 Fax: +49-8142-66989-80 Email: hs at denx.de
More information about the U-Boot
mailing list