pgix
Posts: 34
Joined: Wed Jan 25, 2012 3:53 pm
Contact: Website

Issue with Porting to ARM

Thu Mar 12, 2015 1:55 pm

Hi All,

I have an IA32/AMD64 hobby OS which has got quite a long way and I'd like to port it to the Raspberry Pi for a more "serious" embedded project. I had a previous go a long time ago with the original model B but am revisiting it now.

Anyway - I've taken my first steps using this page as a template. My problem is that kmain doesn't seem to get called. I'm using a gcc arm-none-eabi cross-compiler. Here's the relevant part of my code:

Code: Select all

        ...
	.extern kmain
	ldr r3, =kmain
	blx r3
        ...
We definitely reach this section after clearing the .bss, because code to light the OK LED works if placed before this line. The disassembly (arm-none-eabi-objdump) is:

Code: Select all

   [BSS cleared here and SP set to 0x8000]
   ...
    802c:	e59f304c 	ldr	r3, [pc, #76]	; 8080 <loop$+0xc>
    8030:	e12fff33 	blx	r3
   ...
00008074 <loop$>:
    8074:	eafffffe 	b	8074 <loop$>
    8078:	0000b000 	.word	0x0000b000
    807c:	0000c000 	.word	0x0000c000
    8080:	00008240 	.word	0x00008240
    8084:	20200000 	.word	0x20200000
   ...
   [ld places various functions here, including my _init and _fini functions for initialising global objects]
   ...
00008240 <kmain>:
    8240:	e92d4800 	push	{fp, lr}
    8244:	e28db004 	add	fp, sp, #4
    8248:	e24dd018 	sub	sp, sp, #24
   ...
..where kmain is declared as 'extern "C"' from the C++ portion of my kernel. As you can see, my assembly call to kmain seems to be turned in to a call to somewhere in the middle of my LED-flashing idle loop at 0x8080, instead of correctly pointing to 0x8240. My linker script is a very basic affair with initial alignment at 0x8000 and sections aligned on 4KiB boundaries.

I'd be happy to provide more source code or detail, but think that the above information is all that should be needed. I'm very familiar with intel-syntax ASM, but much less comfortable with ARM assembly.

Can anyone help with what might be going wrong with that strange call address loaded in to r3?

Many thanks,
Adam Jones

User avatar
rpdom
Posts: 16070
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: Issue with Porting to ARM

Thu Mar 12, 2015 2:01 pm

This code loads R3 with the contents of the location 8080 (PC + 76), then uses that as the destination address.

Code: Select all

802c:   e59f304c    ldr   r3, [pc, #76]   ; 8080 <loop$+0xc>
8030:   e12fff33    blx   r3
Location 8080 contains 8240

Code: Select all

8080:   00008240    .word   0x00008240
So it loads R3 with 8240, then jumps to that location where your code is.

pgix
Posts: 34
Joined: Wed Jan 25, 2012 3:53 pm
Contact: Website

Re: Issue with Porting to ARM

Thu Mar 12, 2015 2:05 pm

Ah - that explains it! I thought I was loading an immediate.

I now just need to find why a call to _lightLED as the first line of kmain doesn't light the LED!

Thanks,
Adam

Edit: Time to get qemu, I think!

User avatar
DavidS
Posts: 4334
Joined: Thu Dec 15, 2011 6:39 am
Location: USA
Contact: Website

Re: Issue with Porting to ARM

Thu Mar 12, 2015 3:24 pm

pgix wrote:Ah - that explains it! I thought I was loading an immediate.

I now just need to find why a call to _lightLED as the first line of kmain doesn't light the LED!

Thanks,
Adam

Edit: Time to get qemu, I think!
QEMU would run very slow on a RPi.

Though ARM assembly is simple, way simpler than "Intel" assembly. I do not like the syntax used by GAS, thpough the same goes for Intel Assembly, and 680x0 assembly, GAS is terible.

Remember that you can not load a large constant unless all the significant bits are together (a rotated load), do to it having to fit in the instruction word. So you load it from memory and go from there.

It seems that if you are never going to return that loading the address directly to R15 makes more sence than using a branch with link, though that is just me. R15 is the program pointer (or PC), and can be directly manipulated just like any other register (none of the X86 stuff of having to use this register and only this register for many things, R15 and R14 are the only registers with special meaning on the ARM, and only in the use for a PC).
RPi = The best ARM based RISC OS computer around
More than 95% of posts made from RISC OS on RPi 1B/1B+ computers. Most of the rest from RISC OS on RPi 2B/3B/3B+ computers

pgix
Posts: 34
Joined: Wed Jan 25, 2012 3:53 pm
Contact: Website

Re: Issue with Porting to ARM

Thu Mar 12, 2015 5:38 pm

This is a rather embarrassing schoolboy error which I was not going to admit to, but in case anyone else is as daft as me, this answer may help.

Having solved the initial problem, I discovered that I was getting strange freezes depending on whether I called my C++ code from assembly using BL or BLX instructions, along with the other sort of weirdness that you normally associate with the toolchain.

Anyway, I eventually realised that the problem was caused by the fact that raspbootcom / raspbootin, which I was using to transfer my kernel via UART does not actually relocate ELF files. I now objcopy my ELF kernel to plain binary and the problem is gone! My basic (debug-level) UART driver now works and I no longer have to work in the dark as I can register-dump via UART.

Many thanks to anyone who worked on this and sorry for the daft mistake.

Cheers,
Adam

mrvn
Posts: 58
Joined: Wed Jan 09, 2013 6:50 pm

Re: Issue with Porting to ARM

Sun Apr 19, 2015 9:32 am

Hi there, author of Raspbootin here.

The Raspbootin is not ment to load an ELF file because that isn't what the Raspberry Pi normaly does. It's ment to load the same flat binary image that you would load directly from SDcard, except load it over serial. So that ELF isn't working is expected behaviour.

Also noteworthy is that Raspbootin does not itself handle a initrd but it passes on the initrd loaded from SDCard if there was one. Just make sure not to load it at 0x200000, put it somewhere higher. Raspbootin copies itself to 0x200000 to make room for downloading the real kernel without checking if that overlaps the initrd. You can change that address in the source if you need to.

Enjoy, Mrvn

Return to “Bare metal, Assembly language”