Try   HackMD

Hello world for bare metal ARM using QEMU

tags:arm
  • -nographic
    address where the UART0 is mapped: 0x101f1000

test.c

volatile unsigned int * const UART0DR = (unsigned int *)0x101f1000;
 
void print_uart0(const char *s) {
 while(*s != '\0') { /* Loop until end of string */
 *UART0DR = (unsigned int)(*s); /* Transmit char */
 s++; /* Next char */
 }
}
 
void c_entry() {
 print_uart0("Hello world!\n");
}

The QEMU emulator is written especially to emulate Linux guest systems; for this reason its startup procedure is implemented specifically: the -kernel option loads a binary file (usually a Linux kernel) inside the system memory starting at address 0x00010000. The emulator starts the execution at address 0x00000000, where few instructions (already in place) are used to jump at the beginning of the kernel image. The interrupt table of ARM cores, usually placed at address 0x00000000, is not present, and the peripheral interrupts are disabled at startup, as needed to boot a Linux kernel. Knowing this, to implement a working emulation I need to considerate a few things:
The software must be compiled and linked to be placed at 0x00010000
I need to create a binary image of our program
I can ignore interrupt handling for now

startup.s

.global _Reset
_Reset:
 LDR sp, =stack_top
 BL c_entry
 B .

test.ld

ENTRY(_Reset)
SECTIONS
{
 . = 0x10000;
 .startup . : { startup.o(.text) }
 .text : { *(.text) }
 .data : { *(.data) }
 .bss : { *(.bss COMMON) }
 . = ALIGN(8);
 . = . + 0x1000; /* 4kB of stack memory */
 stack_top = .;
}

compile and linking

$ arm-none-eabi-as -mcpu=arm926ej-s -g startup.s -o startup.o
$ arm-none-eabi-gcc -c -mcpu=arm926ej-s -g test.c -o test.o
$ arm-none-eabi-ld -T test.ld test.o startup.o -o test.elf
$ arm-none-eabi-objcopy -O binary test.elf test.bin

test

$ qemu-system-arm -M versatilepb -m 128M -nographic -s -S -kernel test.bin

host gdb

gdb-multiarch file.elf
target remote localhost:1234

出處:https://balau82.wordpress.com/2010/02/28/hello-world-for-bare-metal-arm-using-qemu/