[U-Boot,2/2] hello_world.c: fix entry point in case of arm thumb binary

Message ID 20170812090346.7887-3-max.krummenacher@toradex.com
State Superseded
Delegated to: Tom Rini
Headers show

Commit Message

Max Krummenacher Aug. 12, 2017, 9:03 a.m.
If compiling for thumb the U-Boot 'go' command can not jump to the entry
point, as the jump will be done in the assumption that the code jumped to
is using the arm instruction set.

So add add a simple forwarder in arm instruction set which then jumps
to the 'real' entry.

Signed-off-by: Max Krummenacher <max.krummenacher@toradex.com>

---

 examples/standalone/hello_world.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

Comments

Wolfgang Denk Aug. 12, 2017, 6:39 p.m. | #1
Dear Max,

In message <20170812090346.7887-3-max.krummenacher@toradex.com> you wrote:
> If compiling for thumb the U-Boot 'go' command can not jump to the entry
> point, as the jump will be done in the assumption that the code jumped to
> is using the arm instruction set.
> 
> So add add a simple forwarder in arm instruction set which then jumps
> to the 'real' entry.

This description makes no sense to me.  Whatever you do, the address
where the image starts executuin is what is called the entry point.
Whether this is needs special code to swutch to thumb mode or not
does not make any difference.  Whichever address you use with the
"go" command is the "entry point".

Also, can the mode switching not be done inside the body of the
regular hello_world() function?  This would be much better as it
wuld allow to always use the same method to determine the entry
point address (line running "nm" on the binary and grepping for the
name "hello_world").  With your code, you would have to fix all
documentation and explain that the entry pooint name is suddenly
domething totally different (and an unexpected, unusal name like
"dummy2" as well) for thumb images.

Sorry, but this does not seem a good idea to me.

Naked-by: Wolfgang Denk <wd@denx.de>

Best regards,

Wolfgang Denk
Max Krummenacher Aug. 12, 2017, 9:31 p.m. | #2
Dear Wolfgang

Am Samstag, den 12.08.2017, 20:39 +0200 schrieb Wolfgang Denk:
> Dear Max,
> 
> In message <20170812090346.7887-3-max.krummenacher@toradex.com> you wrote:
> > 
> > If compiling for thumb the U-Boot 'go' command can not jump to the entry
> > point, as the jump will be done in the assumption that the code jumped to
> > is using the arm instruction set.
> > 
> > So add add a simple forwarder in arm instruction set which then jumps
> > to the 'real' entry.
> 
> This description makes no sense to me.  Whatever you do, the address
> where the image starts executuin is what is called the entry point.
> Whether this is needs special code to swutch to thumb mode or not
> does not make any difference.  Whichever address you use with the
> "go" command is the "entry point".
> 
> Also, can the mode switching not be done inside the body of the
> regular hello_world() function?  This would be much better as it
> wuld allow to always use the same method to determine the entry
> point address (line running "nm" on the binary and grepping for the
> name "hello_world").  With your code, you would have to fix all
> documentation and explain that the entry pooint name is suddenly
> domething totally different (and an unexpected, unusal name like
> "dummy2" as well) for thumb images.

This again stems from my assumption that one has to write the
standalone application in a way that the entry point is actually
linked to the beginning of the binary.

One cannot put the mode switching from thumb to arm instruction set
inside the body of a C function, as the entry code prepended by
the compiler would be in thumb and thus an exception would occur
before the mode switching code gets executed.

Probably one can add a pragma conditionally so that the entry
function gets compiled in arm instruction set. I investigate
further and send a v2.

Max
> 
> Sorry, but this does not seem a good idea to me.
> 
> Naked-by: Wolfgang Denk <wd@denx.de>
> 
> Best regards,
> 
> Wolfgang Denk
>
Wolfgang Denk Aug. 14, 2017, 7:46 p.m. | #3
Dear Max,

In message <1502573515.17070.20.camel@gmail.com> you wrote:
> 
> This again stems from my assumption that one has to write the
> standalone application in a way that the entry point is actually
> linked to the beginning of the binary.

No, this stems from your confusion of load address and entry point
address.  Of course it is possib;e that the entry point is at the
very beginning of the binary.  In that case you must load the image
such into memory, that the start addresss of the binary is the same
as the entry point address.

But the load address is not the start of the binary in memory - it
is the start address of the _image_.   Almost always the bianry will
be just a payload within the image - in the most simple cases of the
lecagy uImage files the binary payload will be preceeded by a 64
byte image header.  So when your load addess is set to 0x100000,
the binary will NOT start at this address, but at an offset of 64
bytes.  So the entry poin can NEVER be the same as the load address,
as this is outside of the image payload.

> One cannot put the mode switching from thumb to arm instruction set
> inside the body of a C function, as the entry code prepended by
> the compiler would be in thumb and thus an exception would occur
> before the mode switching code gets executed.

If this cannot be a regular C funtion, we should still be able to
provide some trampoline code using the same name.  My main goal is
to avoid confugion to the user who expects that he can look up the
entry point address in the nm ouutput under the well-known name.

> Probably one can add a pragma conditionally so that the entry
> function gets compiled in arm instruction set. I investigate
> further and send a v2.

Thanks.

Best regards,

Wolfgang Denk
Tom Rini Aug. 14, 2017, 9:15 p.m. | #4
On Sat, Aug 12, 2017 at 11:03:46AM +0200, Max Krummenacher wrote:

> If compiling for thumb the U-Boot 'go' command can not jump to the entry
> point, as the jump will be done in the assumption that the code jumped to
> is using the arm instruction set.
> 
> So add add a simple forwarder in arm instruction set which then jumps
> to the 'real' entry.
> 
> Signed-off-by: Max Krummenacher <max.krummenacher@toradex.com>

This looks like a special case of what we're doing in f99993c10882 and
dc89c6fb778e and perhaps we need to move that kind of fixup around to
somewhere else, as I assume you've found this problem on a custom
application?  Or are you utilizing hello_world in some test suites?
Just curious, thanks!
Max Krummenacher Aug. 15, 2017, 12:24 p.m. | #5
Hello all

Am Montag, den 14.08.2017, 17:15 -0400 schrieb Tom Rini:

On Sat, Aug 12, 2017 at 11:03:46AM +0200, Max Krummenacher wrote:



If compiling for thumb the U-Boot 'go' command can not jump to the entry
point, as the jump will be done in the assumption that the code jumped to
is using the arm instruction set.

So add add a simple forwarder in arm instruction set which then jumps
to the 'real' entry.

Signed-off-by: Max Krummenacher <max.krummenacher@toradex.com>


This looks like a special case of what we're doing in f99993c10882 and
dc89c6fb778e and perhaps we need to move that kind of fixup around to
somewhere else, as I assume you've found this problem on a custom
application?  Or are you utilizing hello_world in some test suites?
Just curious, thanks!


I guess the difference to f99993c10882 and dc89c6fb778e is that one
knows from armv7m that the CPU is thumb only while on an armv7a
potentially both arm and thumb mode can be used.

Actually a customer asked how to run hello_world.bin, so I
tested with our regular defconfig and the produced hello_world.bin.

I'm having 'CONFIG_SYS_THUMB_BUILD=y' in e.g.
configs/colibri_imx6_nospl_defconfig thus all of the U-Boot code
including hello_world.c is compiled for thumb.

If I boot that U-Boot, load hello_world.bin into RAM at
CONFIG_STANDALONE_LOAD_ADDR and execute 'go CONFIG_STANDALONE_LOAD_ADDR'
I get output from the go command and then the CPU resets.

    Colibri iMX6 # tftp 0x12000000 hello_world.bin
      ...
    Colibri iMX6 # go 0x12000000                                                     
    ## Starting application at 0x12000000 ...                                       

With the patch I get the expected output.

But actually calling the 'go' command with bit 0 set works. So if
the user knows that he is having a thumb binary that would fix
the issue as well. With the current implementation the following works:

    Colibri iMX6 # go 0x12000001                                                    
    ## Starting application at 0x12000001 ...                                       
    Example expects ABI version 9                                                   
    Actual U-Boot ABI version 9                                                     
    Hello World                                                                     
    argc = 1                                                                        
    argv[0] = "0x12000001"                                                          
    argv[1] = "<NULL>"                                                              
    Hit any key to exit ...                                                         

Max

Patch

diff --git a/examples/standalone/hello_world.c b/examples/standalone/hello_world.c
index bd8b392315..0b859ca4bd 100644
--- a/examples/standalone/hello_world.c
+++ b/examples/standalone/hello_world.c
@@ -8,6 +8,21 @@ 
 #include <common.h>
 #include <exports.h>
 
+/*
+ * Make thumb work by providing a forwarder to the (thumb) entry point
+ * compiled for arm instruction set.
+ * Don't compile this for thumb only CPUs.
+ */
+#if defined(__thumb__) && defined(__ARM_ARCH_ISA_ARM)
+void __attribute__((unused)) __attribute__ ((naked)) dummy2(void)
+{
+asm volatile( \
+"	.code 32\n" \
+"	.arm\n" \
+"	ldr pc,=hello_world\n");
+}
+#endif
+
 int hello_world (int argc, char * const argv[])
 {
 	int i;