[U-Boot] [PATCH v5] Fix board init code to respect the C runtime environment

Simon Glass
2015-11-19T01:05:07Z

Hi Albert,

On 17 November 2015 at 05:59, Albert ARIBAUD <albert.u.boot@aribaud.net> wrote:
> Hello Simon,
>
> On Mon, 16 Nov 2015 21:11:38 -0700, Simon Glass <sjg@chromium.org>
> wrote:
>
>> > +++ b/arch/arm/lib/crt0.S
>> > @@ -82,9 +82,11 @@ ENTRY(_main)
>> > #else
>> > bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
>> > #endif
>> > + bl board_init_f_get_reserve_size
>> > + sub sp, sp, r0
>> > + mov r9, sp
>>
>> Why do you need that?
>
> To set gd in ARM architecture, as arch_setup_gd() may not work for
> ARM, see my 'Note about the ARM case' in my answer dated Sun, 15 Nov
> 2015 14:51:04 +0100 for details:
>
> https://www.mail-archive.com/u-boot at lists.denx.de/msg192494.html
>

OK I understand that now.

> I shall post a 2-patch v6 with this fix standalone as 1/2 and the rest
> of the changes as 2/2.
>
>> > +++ b/common/init/board_init.c
>> > @@ -21,39 +21,121 @@ DECLARE_GLOBAL_DATA_PTR;
>> > #define _USE_MEMCPY
>> > #endif
>> >
>> > -/* Unfortunately x86 can't compile this code as gd cannot be assigned */
>> > -#ifndef CONFIG_X86
>> > +/* Unfortunately x86 or ARM can't compile this code as gd cannot be assigned */
>> > +#if !defined(CONFIG_X86) && !defined(CONFIG_ARM)
>> > __weak void arch_setup_gd(struct global_data *gd_ptr)
>> > {
>> > gd = gd_ptr;
>> > }
>> > -#endif /* !CONFIG_X86 */
>> > +#endif /* !CONFIG_X86 && !CONFIG_SYS_THUMB_BUILD */
>> >
>> > -ulong board_init_f_mem(ulong top)
>> > +/*
>> > + * Compute size of space to reserve on stack for use as 'globals'
>> > + * and return size request for reserved area.
>> > + *
>> > + * Notes:
>> > + *
>> > + * Actual reservation cannot be done from within this function as
>> > + * it requires altering the C stack pointer, so this will be done by
>> > + * the caller upon return from this function.
>> > + *
>> > + * IMPORTANT:
>> > + *
>> > + * The return value of this function has two uses:
>> > + * - it determines the amount of stack reserved for global data and
>> > + * the malloc arena;
>>
>> early malloc() area
>
> "Arena", and "malloc arena", are established designations for the
> memory space used by malloc implementations; and I prefer to use this
> more specific term, as people may use it as a search keyword when
> looking for malloc related stuff.

Arena is OK, but can you please mention 'early' each time? It's
confusing otherwise. I think we should have a clear distinction
between the early malloc() and full malloc().

>
>> Another option would be to pass the address and have this function
>> return the new address. That would simplify the assembly code slightly
>> for all archs I think. It would also allow you to align the address
>> for sure, whereas at present it only works if the original address was
>> aligned, and CONFIG_SYS_MALLOC_F_LEN is aligned.
>
> Good point, with a few caveats though.
>
> Regarding alignment of CONFIG_SYS_MALLOC_F_LEN:
>
> Indeed, no attempt is made to check that it is aligned (and no attempt
> is made in the original code either) -- all the more since there is no
> strict definition of what it should be aligned to. There is, actually,
> no indication that it should be aligned, although it will probably only
> be used up until the last full 4-byte-word (or 8-byte word for 64-bit
> architectures). In fact, the alignment of CONFIG_SYS_MALLOC_F_LEN does
> not matter much, see (*) below.
>
> Regarding alignment of the original/'top' address:
>
> This top address is the SP for all architectures, and at least for ARM,
> it is aligned to an 8-byte boundary, as this is an ARM architecture
> EABI requirement. For other architectures, I cannot claim it is, but I
> suspect all initial values of SP, which generally are CONFIG_SPL_STACK
> or CONFIG_SYS_INIT_SP_ADDR, are (sufficiently) aligned.
>
> And if CONFIG_SPL_STACK and CONFIG_SYS_INIT_SP_ADDR are not
> (sufficiently) aligned in their definition, then either we can fix
> these definitions (and that of CONFIG_SYS_MALLOC_F_LEN too, while we
> are at it), or, if we can only fix this at run time, then this should be
> done where the stack pointer is altered, in the crt0.S file or whatever
> its equivalent is for any given architecture, outside the C environment.
>
> But that will have to go in another patch dealing with alignment.

If you can have it so that the stack top equals the global_data
bottom, then we should be OK.

>
> (*)
>
> Indeed board_init_f_get_reserve_size may have to respect some location
> or size alignment for each of the chunks it reserves. Right now, for
> instance, GD is aligned to a 16-byte boundary, and the malloc arena is
> aligned by virtue of the rounded value of CONFIG_SYS_MALLOC_F_LEN.
>
> And yes, should some new reservation be made beside GD and the malloc
> arena, it might require some specific alignment not dealt with so far;
> for instance, we may need to reserve some 4KB-aligned chunk for memory
> management purposes, or whatever, and there is no guarantee that the
> original stack is 4KB-aligned.
>
> In that light, ulong board_init_f_get_reserve_size(void) does not
> permit controlled alignment, whereas ulong board_init_f_reserve(ulong
> top) does, since we can round 'top' down to any value we like.
>
> Note, however, that it will not simplify assembly code: it will turn a
> subtraction from sp into an assignment to sp, which is not simpler, and
> it will add an assignment to whatever register represents the first
> argument, since we'll turn a (void) function into a (ulong top)
> function, so all in all, it will add one assembly instruction with
> respect to the 'ulong board_init_f_get_reserve_size(void)' approach.

True, but now we are just passing values around rather than doing
arithmetic in assembler.

>
>> > + /* set GD unless architecture did it already */
>> > +#if !defined(CONFIG_X86) && !defined(CONFIG_ARM)
>> > arch_setup_gd(gd_ptr);
>>
>> Why does this not work for ARM?
>
> See above, but note that whatever the architecture, gd will be useable
> after this call, so :
>
>> > +#endif
>> > + /* next alloc will be higher by one GD plus 16-byte alignment */
>> > + base += roundup(sizeof(struct global_data), 16);
>> > +
>> > + /*
>> > + * record malloc arena start
>> > + */
>> >
>> > #if defined(CONFIG_SYS_MALLOC_F)
>> > - top -= CONFIG_SYS_MALLOC_F_LEN;
>> > - gd->malloc_base = top;
>> > + /* go down one malloc arena */
>> > + gd->malloc_base = base;
>>
>> gd_ptr?
>
> gd works at this point, and I want to avoid any aliasing issue.

I don't really understand that, but if you want to use gd I think it
would be worth a one-line comment.

>
>> Regards,
>> Simon
>
> Thanks for your comments! I'll turn
>
> ulong board_init_f_get_reserve_size(void)
>
> into
>
> ulong board_init_f_get_reserve(ulong top)
>
> So that arbitrary alignments will be possible, and I will move the r9
> fix into its own patch.

OK sounds good.

>
> Amicalement,
> --
> Albert.