Question: Multiple board support is broken
Alexander Shiyan
shc_work at mail.ru
Sat Dec 8 03:28:11 EST 2012
On Fri, 7 Dec 2012 16:17:54 +0000
Russell King - ARM Linux <linux at arm.linux.org.uk> wrote:
> > Today I was tested multiple boards (not multiplatform) in the kernel
> > and found problems with booting.
>
> Err, I test this almost constantly and it works, and it's been working
> 100% correctly for about the last 12 years. There is no problem here.
>
> > Exacly, if multiple boards defined
> > in. config, we can proceed to boot only the last (determined by mach number).
>
> The mach-types file doesn't have anything to do with which board gets chosen.
> That file just provides the IDs, and a bunch of _optimized_ macros to
> allow the compiler to perform optimizations.
>
> Let's look at how this works today - let me pull out two entries:
>
> #ifdef CONFIG_ARCH_EBSA285
> # ifdef machine_arch_type
> # undef machine_arch_type
> # define machine_arch_type __machine_arch_type
> # else
> # define machine_arch_type MACH_TYPE_EBSA285
> # endif
> # define machine_is_ebsa285() (machine_arch_type == MACH_TYPE_EBSA285)
> #else
> # define machine_is_ebsa285() (0)
> #endif
>
> #ifdef CONFIG_ARCH_NETWINDER
> # ifdef machine_arch_type
> # undef machine_arch_type
> # define machine_arch_type __machine_arch_type
> # else
> # define machine_arch_type MACH_TYPE_NETWINDER
> # endif
> # define machine_is_netwinder() (machine_arch_type == MACH_TYPE_NETWINDER)
> #else
> # define machine_is_netwinder() (0)
> #endif
>
> #ifndef machine_arch_type
> #define machine_arch_type __machine_arch_type
> #endif
>
> Now, if CONFIG_ARCH_EBSA285=y and CONFIG_ARCH_NETWINDER=n, then follow
> through what the preprocessor does. In the first case, machine_arch_type
> is _not_ defined as a pre-processor symbol, so the "ifdef" is false.
> That means machine_arch_type gets defined as MACH_TYPE_EBSA285.
>
> machine_is_ebsa285() gets defined as (machine_arch_type == MACH_TYPE_EBSA285)
> and when all the macro subsitutions occur (which happens where it's used)
> this ends up becoming (MACH_TYPE_EBSA285 == MACH_TYPE_EBSA285). This is
> always true, so any code inside an if (machine_is_ebsa285()) {} block will
> be compiled into the kernel and will be executed unconditionally - which
> is exactly what we want.
>
> Now, machine_is_netwinder() gets defined as constant (0). This is always
> false, so any code inside an if (machine_is_netwinder()) {} block will
> be optimized away - exactly what we want. This isn't affected by the
> machine_arch_type definition.
>
> Next, you can do the same thing for the CONFIG_ARCH_EBSA285=n and
> CONFIG_ARCH_NETWINDER=y case, and you'll end up with similar results.
>
> Finally for the case where CONFIG_ARCH_EBSA285=y and CONFIG_ARCH_NETWINDER=y.
> In this case, it starts off just like the CONFIG_ARCH_EBSA285=y case above.
> When we hit the CONFIG_ARCH_NETWINDER block a very important change happens.
> This time machine_arch_type is already defined.
>
> So, what happens is machine_arch_type first gets undefined to avoid any
> compiler warnings about multiple definitions. We then define
> machine_arch_type to be the C variable __machine_arch_type.
>
> This makes any references to (machine_arch_type == MACH_TYPE_WHATEVER)
> become a runtime interpreted condition, which occurs for any machine type
> that has its config symbol enabled. So, machine_is_ebsa285() becomes
> (__machine_arch_type == MACH_TYPE_EBSA285) and machine_is_netwinder()
> becomes (__machine_arch_type == MACH_TYPE_NETWINDER), while other
> platforms machine_is_xxx() macros remain defined to constant 0.
>
> So, this all works exactly as we want. There is no bug here.
Apparently the problem is that I have a custom symbol for their own board,
but I specify an existing ID in the MACHINE_START. The initial boot is fine,
because support for the ID is in the kernel, but the mach_desc is taken from
a different machine. Below is a test program to demonstrate. In this test I
boot kernel with ID=4 and I have a valid machines with ID=4 and 5, but symbol
associated with ID=4 is missing. This case will a result boot a machine ID=5.
How to solve the problem, I do not know yet...
<<< test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#define CONFIG_ARCH_EBSA285 1
#define CONFIG_ARCH_NETWINDER 1
#define MACH_TYPE_EBSA285 4
#define MACH_TYPE_NETWINDER 5
#ifdef CONFIG_ARCH_EBSA285
# ifdef machine_arch_type
# undef machine_arch_type
# define machine_arch_type __machine_arch_type
# else
# define machine_arch_type MACH_TYPE_EBSA285
# endif
# define machine_is_ebsa285() (machine_arch_type == MACH_TYPE_EBSA285)
#else
# define machine_is_ebsa285() (0)
#endif
#ifdef CONFIG_ARCH_NETWINDER
# ifdef machine_arch_type
# undef machine_arch_type
# define machine_arch_type __machine_arch_type
# else
# define machine_arch_type MACH_TYPE_NETWINDER
# endif
# define machine_is_netwinder() (machine_arch_type == MACH_TYPE_NETWINDER)
#else
# define machine_is_netwinder() (0)
#endif
#ifndef machine_arch_type
#define machine_arch_type __machine_arch_type
#endif
unsigned int __machine_arch_type = MACH_TYPE_EBSA285; //From bootloader
int main(int argc, char** argv)
{
if (machine_is_ebsa285())
printf("machine_is_ebsa285()\n");
if (machine_is_netwinder())
printf("machine_is_netwinder()\n");
printf(" machine_arch_type=%u\n", machine_arch_type);
printf("__machine_arch_type=%u\n", __machine_arch_type);
return 0;
}
>>>
shc at shc /home/git/test $ ./test
machine_is_netwinder()
machine_arch_type=5
__machine_arch_type=4
--
Alexander Shiyan <shc_work at mail.ru>
More information about the linux-arm-kernel
mailing list