Little Tree
Little Tree

Reputation: 95

Aarch64 baremetal Hello World program on QEMU

I have compiled and ran a simple hello world program on ARM Foundation Platform. The code is given below.

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("Hello world!\n");
    return 0;
}

This program is compiled and linked using ARM GNU tool chain as given below.

$aarch64-none-elf-gcc -c -march=armv8-a -g hello.c hello.o
  aarch64-none-elf-gcc: warning: hello.o: linker input file unused because linking not done


$aarch64-none-elf-gcc -specs=aem-ve.specs -Wl,-Map=linkmap.txt hello.o -o hello.axf

I could successfully execute this program on ARM Foundation Platform (I think, foundation platform is similar to ARM Fixed Virtual Platform) and it prints "Hello world!"

The contents of 'aem-ve.specs' file is given below:

cat ./aarch64-none-elf/lib/aem-ve.specs 
# aem-ve.specs
#
# Spec file for AArch64 baremetal newlib, libgloss on VE platform with version 2
# of AngelAPI semi-hosting.
#
# This Spec file is also appropriate for the foundation model.

%rename link old_link

*link:
-Ttext-segment 0x80000000 %(old_link)

%rename lib libc

*libgloss:
-lrdimon

*lib:
cpu-init/rdimon-aem-el3.o%s --start-group %(libc) %(libgloss) --end-group

*startfile:
crti%O%s crtbegin%O%s %{!pg:rdimon-crt0%O%s} %{pg:rdimon-crt0%O%s}

Is it possible to execute the same binary on QEMU? If so could you please share the sample command. If not, could you please share the right and best way to execute it on QEMU?

I have traced instruction execution of Foundation platform using the "trace" option and analysed using 'tarmac-profile' tool and 'Tarmac-calltree' tool. The outputs are given below:

$ ./tarmac-profile hello.trace --image hello.axf
Address     Count       Time        Function name
0x80000000  1           120001      
0x80001030  1           30001       register_fini
0x80001050  1           60001       deregister_tm_clones
0x800010c0  1           210001      __do_global_dtors_aux
0x80001148  1           23500001    frame_dummy
0x800012c0  1           10480001    main
0x80002000  1           40001       main
0x80003784  1           360001      main
0x80003818  1           460001      _cpu_init_hook
0x80003870  1           590001      _write_r
0x800038d0  1           1090001     __call_exitprocs
...
...
./tarmac-calltree hello.trace --image hello.axf 


o t:10000 l:2288 pc:0x80001148 - t:23510000 l:7819 pc:0x80008060 : frame_dummy
  - t:240000 l:2338 pc:0x800011a8 - t:720000 l:2443 pc:0x800011ac
    o t:250000 l:2340 pc:0x80003818 - t:710000 l:2442 pc:0x80003828 : _cpu_init_hook
      - t:260000 l:2343 pc:0x8000381c - t:320000 l:2354 pc:0x80003820
        o t:270000 l:2345 pc:0x80002000 - t:310000 l:2353 pc:0x80002010 : main
      - t:320000 l:2354 pc:0x80003820 - t:700000 l:2436 pc:0x80003824
        o t:330000 l:2356 pc:0x80003784 - t:690000 l:2435 pc:0x80003814 : main
  - t:760000 l:2453 pc:0x800011bc - t:2010000 l:2970 pc:0x800011c0
    o t:770000 l:2455 pc:0x80004200 - t:2000000 l:2969 pc:0x800042c0 : memset
  - t:2010000 l:2970 pc:0x800011c0 - t:4870000 l:3587 pc:0x800011c4
    o t:2020000 l:2972 pc:0x80007970 - t:4860000 l:3586 pc:0x80007b04 : initialise_monitor_handles
      - t:2960000 l:3165 pc:0x80007b24 - t:4340000 l:3465 pc:0x80007b28

I have tried the following method to execute on QEMU, without any success. I have started the QEMU with gdb based debugging through TCP Port

$ qemu-system-aarch64 -semihosting -m 128M -nographic  -monitor none -serial stdio  -machine virt,gic-version=2,secure=on,virtualization=on -cpu cortex-a53 -kernel hello.axf -S -gdb tcp::9000

The result of debug session is given below:

gdb) target remote localhost:9000
Remote debugging using localhost:9000
_start () at /data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/libgloss/aarch64/crt0.S:90
90  /data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/libgloss/aarch64/crt0.S: No such file or directory.
(gdb) si

<The system hangs here>

I have tried to disassemble the code using gdb and its output is given below. It looks like the code is not loaded correctly

(gdb) disas frame_dummy
Dump of assembler code for function frame_dummy:
   0x0000000080001110 <+0>: udf #0
   0x0000000080001114 <+4>: udf #0
   0x0000000080001118 <+8>: udf #0
   0x000000008000111c <+12>:    udf #0
 
  0x0000000080001120 <+16>: udf #0
   0x0000000080001124 <+20>:    udf #0
   0x0000000080001128 <+24>:    udf #0
   0x000000008000112c <+28>:    udf #0
   0x0000000080001130 <+32>:    udf #0
   0x0000000080001134 <+36>:    udf #0
   0x0000000080001138 <+40>:    udf #0
   0x000000008000113c <+44>:    udf #0
   0x0000000080001140 <+48>:    udf #0
   0x0000000080001144 <+52>:    udf #0
End of assembler dump.

Could you please shed some light on this. Any hint given is appreciated very much.

Upvotes: 1

Views: 461

Answers (1)

Peter Maydell
Peter Maydell

Reputation: 11393

The Foundation Model and the QEMU 'virt' board are not the same machine type. They have different devices at different physical addresses, and in particular they do not have RAM at the same address. To run bare metal code on the 'virt' machine type you will need to adjust your code. This is normal for bare metal -- the whole point is that you are running directly on some piece of (emulated) hardware and need to match the details of it.

Specifically, the minimum change you need to make here is that the RAM on the 'virt' board starts at 0x4000_0000, not the 0x8000_0000 that the Foundation Model uses. There may be others as well, but that is the immediate cause of what you're seeing.

Upvotes: 1

Related Questions