[coreboot] Patch merged into coreboot/master: 026bbda ARM: remove code that is IMHO a dangerous design

gerrit at coreboot.org gerrit at coreboot.org
Mon Mar 4 19:43:20 CET 2013

the following patch was just integrated into master:
commit 026bbda071161ad56822dceaabea03bceefac9ac
Author: Ronald G. Minnich <rminnich at gmail.com>
Date:   Mon Mar 4 09:46:31 2013 -0800

    ARM: remove code that is IMHO a dangerous design
    OK, this is tl;dr. But I need to write this in hopes we make
    sure we don't put code like this into coreboot. Ever.
    Our excuse in this case is that it was imported, not obviously wrong,
    and easily changed. It made sense to get it in, make it work, then
    do a cleanup pass, because changing everything up front is almost
    impossible to debug.
    The exynos code has bunch of base register values, e.g.
    These are base addresses of things that look like a memory-mapped
    struct. To get these to a pointer, they created the following macro,
    which creates an inline function.
    static inline unsigned int samsung_get_base_##device(void)	\
    {								\
    	return cpu_is_exynos5() ? EXYNOS5_##base : 0;		\
    And then invoke it 31 times in a .h file, e.g.:
    to create 31 functions.
    And then use it:
            struct exynos5_clock *clk =
    	                (struct exynos5_clock *)samsung_get_base_clock();
    OK, what's wrong with this? It's easier to ask what's right with it. Answer: nothing.
    I have a long list of what's wrong, and I may leave some things out,
    but here goes:
    1. the "function" can return a NULL if we're not on exynos5. Most uses of the code
       don't check the return value.
    2. And why would this function be running, if we're not on an exynos5? Why compile it in?
    3. Note the cast everywhere a samsung_get_base_xxx is used.
       The function returns an untyped variable, requiring the *user* to get two
       things right: the cast, and the function invocation. One can replace that _clock(); with
       _power(); in the code above, and they will be referencing the wrong registers, and
       they'll never get an error!
       We have a C compiler; use it to type data.
    4. You're generating 31 functions using cpp each and every time the file is included.
       The C compiler has to parse these each time. It's not at all like a simple cpp
       macro which is only generated on use.
    5. You can't tags or etags this code
    6. In fact, any kind of analysis tool will be unable to do anything with this cpp magic.
    That's only a partial list.
    So what's the right way to do it? Just make typed constants, viz:
    Or, since I expect people will want the lower case function syntax, I've left
    it that way:
    Now we've got something that is efficient, and we don't even need to protect with
    any more.
    Hence this change. We've got something that is type checked, does not require users to
    cast on each use, will catch simple programming errors, can be analyzed with standard tools,
    and builds faster.
    So if we make a mistake:
           struct exynos5_clock *clk =
    We'll see it:
    src/cpu/samsung/exynos5250/clock.c: In function 'get_pll_clk':
    src/cpu/samsung/exynos5250/clock.c:183:3: error: initialization from incompatible pointer type [-Werror]
    which we would not have seen before.
    As a minor benefit, it shaves most of a second off the compilation.
    Change-Id: Ie67bc4bc038a8dd1837b977d07332d7d7fd6be1f
    Signed-off-by: Ronald G. Minnich <rminnich at gmail.com>
    Reviewed-on: http://review.coreboot.org/2582
    Tested-by: build bot (Jenkins)

Build-Tested: build bot (Jenkins) at Mon Mar  4 19:41:24 2013, giving +1
Reviewed-By: Ronald G. Minnich <rminnich at gmail.com> at Mon Mar  4 19:43:19 2013, giving +2
See http://review.coreboot.org/2582 for details.


More information about the coreboot mailing list