[PATCH] env: Leave invalid env for nowhere location

Marek Vasut marex at denx.de
Thu Jun 10 03:07:43 CEST 2021


On 6/8/21 9:54 AM, Kunihiko Hayashi wrote:

Hi,

[...]

>>>>>> I would expect that after relocation, if all you have is env_nowhere
>>>>>> driver, the env_nowhere_init() is called again from the first 
>>>>>> for() loop
>>>>>> of env_init() [1], which would set gd->env_valid to ENV_INVALID 
>>>>>> [1], and
>>>>>> that for() loop would exit with ret = -ENOENT [2], so then the 
>>>>>> last part
>>>>>> of env_init() would check for ret == -ENOENT and update 
>>>>>> gd->env_addr to
>>>>>> relocated default_environment [3].
>>>>>>
>>>>>> 324  int env_init(void)
>>>>>> 325  {
>>>>>> 326    struct env_driver *drv;
>>>>>> 327    int ret = -ENOENT;
>>>>>> 328    int prio;
>>>>>> 329
>>>>>> 330    for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); 
>>>>>> prio++) {
>>>>>>            /* Part [1] */
>>>>>> 331      if (!drv->init || !(ret = drv->init()))
>>>>>> 332        env_set_inited(drv->location);
>>>>>> 333      if (ret == -ENOENT)
>>>>>> 334        env_set_inited(drv->location);
>>>>>> 335
>>>>>> 336      debug("%s: Environment %s init done (ret=%d)\n", __func__,
>>>>>> 337            drv->name, ret);
>>>>>> 338
>>>>>>            /* Part [2] */
>>>>>> 339      if (gd->env_valid == ENV_INVALID)
>>>>>> 340        ret = -ENOENT;
>>>>>> 341    }
>>>>>> 342
>>>>>> 343    if (!prio)
>>>>>> 344      return -ENODEV;
>>>>>> 345
>>>>>>          /* Part [3] */
>>>>>> 346    if (ret == -ENOENT) {
>>>>>>            /* This should be relocated default_environment address */
>>>>>> 347      gd->env_addr = (ulong)&default_environment[0];
>>>>>> 348      gd->env_valid = ENV_VALID;
>>>>>> 349
>>>>>> 350      return 0;
>>>>>> 351    }
>>>>>> 352
>>>>>> 353    return ret;
>>>>>> 354  }
>>>>>>
>>>>>> Or am I missing something obvious ?
>>>>>
>>>>> These are called before relocation, and update gd->env_addr to 
>>>>> non-relocated
>>>>> default_environment by [3].
>>>>>
>>>>> After that, gd->env_addr is relocated in initr_reloc_global_data()
>>>>> if CONFIG_SYS_RELOC_GD_ENV_ADDR is defined.
>>>>>
>>>>> | #ifdef CONFIG_SYS_RELOC_GD_ENV_ADDR
>>>>> |     /*
>>>>> |      * Relocate the early env_addr pointer unless we know it is 
>>>>> not inside
>>>>> |      * the binary. Some systems need this and for the rest, it 
>>>>> doesn't hurt.
>>>>> |      */
>>>>> |     gd->env_addr += gd->reloc_off;
>>>>> | #endif
>>>>>
>>>>
>>>> Shouldn't the post-relocation env update happen in env_relocate() ?
>>>
>>> Usually env_relocate() calls env_load() that uses relocated 
>>> gd->env_addr.
>>> It's no problem.
>>>
>>> If CONFIG_SYS_TEXT_BASE is zero, gd->reloc_off becomes illegal.
>>> CONFIG_SYS_RELOC_GD_ENV_ADDR should be disabled in that case.
> 
> Sorry this isn't wrong.
> 
>> But then, if CONFIG_SYS_TEXT_BASE is zero, the env shouldn't be 
>> relocated or how should it behave ?
> 
> I think the env should be relocated if CONFIG_SYS_RELOC_GD_ENV_ADDR=y
> regardless of CONFIG_SYS_TEXT_BASE.
> 
> If CONFIG_POSITION_INDEPENDENT=y and CONFIG_SYS_TEXT_BASE is zero,
> there is something wrong with the calculation of the relocation address 
> about env.

Ah, got it.

> gd->reloc_off is relocated address offset from zero, however,
> gd->env_addr has still non-relocated address.
> 
>  >>>> |     gd->env_addr += gd->reloc_off;
> 
> I think the env should be relocated if CONFIG_SYS_RELOC_GD_ENV_ADDR=y.
> But this code sets gd->env_addr incorrectly.
> 
> In that case, there is a non-relocated <textbase> address instead of
> CONFIG_SYS_TEXT_BASE.
> 
> This should be "gd->env_addr = (gd->env_addr - <textbase>) + 
> gd->reloc_off",
> However, I'm not sure how we get non-relocated <textbase> address.

Maybe what you need to do is store current $pc register when you enter 
U-Boot very early on, in _start function, and then use it here ? 
Although, I am not entirely sure whether this is still possible on arm64.


More information about the U-Boot mailing list